├── .clang-format ├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── data ├── back.png ├── codebrowser.js ├── common.css ├── folder.png ├── indexscript.js ├── indexstyle.css ├── jquery │ ├── images │ │ ├── ui-bg_diagonals-thick_18_b81900_40x40.png │ │ ├── ui-bg_diagonals-thick_20_666666_40x40.png │ │ ├── ui-bg_glass_100_f6f6f6_1x400.png │ │ ├── ui-bg_glass_100_fdf5ce_1x400.png │ │ ├── ui-bg_glass_65_ffffff_1x400.png │ │ ├── ui-bg_gloss-wave_35_f6a828_500x100.png │ │ ├── ui-bg_highlight-soft_100_eeeeee_1x100.png │ │ ├── ui-bg_highlight-soft_75_ffe45c_1x100.png │ │ ├── ui-icons_222222_256x240.png │ │ ├── ui-icons_228ef1_256x240.png │ │ ├── ui-icons_ef8c08_256x240.png │ │ ├── ui-icons_ffd27a_256x240.png │ │ └── ui-icons_ffffff_256x240.png │ ├── jquery-ui.css │ ├── jquery-ui.min.js │ ├── jquery.min.js │ └── js │ │ ├── jquery-1.8.0.min.js │ │ └── jquery-ui-1.8.23.custom.min.js ├── kdevelop.css ├── qtcreator.css ├── solarized.css ├── symbol.html ├── txt.png └── woboq-48.png ├── generator ├── CMakeLists.txt ├── annotator.cpp ├── annotator.h ├── browserastvisitor.h ├── commenthandler.cpp ├── commenthandler.h ├── compat.h ├── embedded_includes.h.in ├── filesystem.cpp ├── filesystem.h ├── generator.cpp ├── generator.h ├── inlayhintannotator.cpp ├── inlayhintannotator.h ├── main.cpp ├── preprocessorcallback.cpp ├── preprocessorcallback.h ├── projectmanager.cpp ├── projectmanager.h ├── projectmanager_systemprojects.cpp.in ├── qtsupport.cpp ├── qtsupport.h └── stringbuilder.h ├── global.h ├── indexgenerator ├── CMakeLists.txt └── indexer.cpp ├── scripts ├── fake_compiler.sh ├── runner.py └── woboq_cc.js └── tests ├── CMakeLists.txt ├── doc.h ├── test.cc └── testqt.cc /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: WebKit 3 | Language: Cpp 4 | Standard: Cpp11 5 | 6 | IndentWidth: 4 7 | SpacesBeforeTrailingComments: 1 8 | TabWidth: 8 9 | UseTab: Never 10 | ContinuationIndentWidth: 4 11 | MaxEmptyLinesToKeep: 3 12 | BreakBeforeBinaryOperators: NonAssignment 13 | BreakBeforeTernaryOperators: true 14 | BreakConstructorInitializers: BeforeColon 15 | BreakConstructorInitializersBeforeComma: true 16 | 17 | BreakBeforeBraces: Custom 18 | BraceWrapping: 19 | AfterClass: true 20 | AfterControlStatement: false 21 | AfterEnum: false 22 | AfterFunction: true 23 | AfterNamespace: false 24 | AfterObjCDeclaration: false 25 | AfterStruct: true 26 | AfterUnion: false 27 | BeforeCatch: false 28 | BeforeElse: false 29 | IndentBraces: false 30 | 31 | ForEachMacros: 32 | - forever # avoids { wrapped to next line 33 | - foreach 34 | - Q_FOREACH 35 | 36 | AccessModifierOffset: -4 37 | ConstructorInitializerIndentWidth: 4 38 | AlignEscapedNewlinesLeft: false 39 | AlignTrailingComments: false 40 | AllowAllParametersOfDeclarationOnNextLine: true 41 | AllowShortIfStatementsOnASingleLine: false 42 | AllowShortLoopsOnASingleLine: false 43 | AllowShortFunctionsOnASingleLine: false 44 | AllowShortEnumsOnASingleLine: false # requires clang-format 11 45 | AlignAfterOpenBracket: true 46 | AlwaysBreakBeforeMultilineStrings: false 47 | AlwaysBreakTemplateDeclarations: true 48 | BinPackParameters: true 49 | ColumnLimit: 100 50 | Cpp11BracedListStyle: false 51 | DerivePointerBinding: false 52 | ExperimentalAutoDetectBinPacking: false 53 | IndentCaseLabels: false 54 | NamespaceIndentation: None 55 | ObjCSpaceBeforeProtocolList: true 56 | PenaltyBreakBeforeFirstCallParameter: 19 57 | PenaltyBreakComment: 60 58 | PenaltyBreakFirstLessLess: 120 59 | PenaltyBreakString: 1000 60 | PenaltyExcessCharacter: 1000000 61 | PenaltyReturnTypeOnItsOwnLine: 60 62 | PointerBindsToType: false 63 | SpaceAfterTemplateKeyword: false 64 | IndentFunctionDeclarationAfterType: false 65 | SpaceAfterControlStatementKeyword: true 66 | SpaceBeforeAssignmentOperators: true 67 | SpaceInEmptyParentheses: false 68 | SpacesInAngles: false 69 | SpacesInCStyleCastParentheses: true 70 | SpacesInParentheses: false 71 | --- 72 | Language: Json 73 | DisableFormat: true 74 | ... 75 | 76 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | build-* 3 | CMakeCache.txt 4 | CMakeFiles 5 | Makefile 6 | cmake_install.cmake 7 | compile_commands.json 8 | codebrowser_* 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | 4 | language: cpp 5 | 6 | script: 7 | - cmake . -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_CXX_FLAGS=-D_GLIBCXX_USE_CXX11_ABI=0 8 | - make -j2 9 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(codebrowser LANGUAGES CXX) 3 | 4 | include(GNUInstallDirs) 5 | set (CMAKE_CXX_STANDARD 20) 6 | 7 | add_subdirectory(generator) 8 | add_subdirectory(indexgenerator) 9 | 10 | install(DIRECTORY data 11 | DESTINATION ${CMAKE_INSTALL_DATADIR}/woboq 12 | ) 13 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | ## Submitting Changes 4 | 5 | In order to allow Woboq to redistribute any of your contributions, we need you to agree to our Contributor License Agreement. 6 | This all handled through https://cla-assistant.io with the following steps: 7 | 8 | * Create a pull request normally 9 | * Click on the button in the comment by the CLA Asistant, if requested to do so 10 | * Agree by signing in with your github account 11 | 12 | You only need to agree to the CLA once for this project. 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [![Logo](https://codebrowser.dev/img/webp/codebrowserLogo.webp)](https://codebrowser.dev) 2 | 3 | This is the generator for Code Browser, formerly created and maintained by [Woboq](https://woboq.com/), 4 | [KDAB](https://kdab.com) wants to thank Woboq to have made available such a great tool to the community in the first place. See https://codebrowser.dev/ for an example. 5 | 6 | The announcement blog: https://woboq.com/blog/codebrowser-introduction.html 7 | 8 | Introduction and Design 9 | ======================= 10 | 11 | There is a pre-processing step on your code that generates static html and 12 | reference database. The output of this phase is just a set of static files that 13 | can be uploaded on any web hoster. No software is required on the server other 14 | than the most basic web server that can serve files. 15 | 16 | While generating the code, you will give to the generator an output directory. 17 | The files reference themselves using relative path. The layout in the output 18 | directory will look like this: 19 | (Assuming the output directory is `~/public_html/mycode`) 20 | 21 | `$OUTPUTDIR/../data/` or `~/public_html/data/` 22 | is where all javascript and css files are located. Those are static files shipped with the code browser, they are not generated. 23 | 24 | `$OUTPUTDIR/projectname` or `~/public_html/mycode/projectname` 25 | contains the generated html files for your project 26 | 27 | `$OUTPUTDIR/refs` or `~/public_html/mycode/refs` 28 | contains the generated "database" used for the tooltips 29 | 30 | `$OUTPUTDIR/include` or `~/public_html/mycode/include` 31 | contains the generated html files for the files in /usr/include 32 | 33 | 34 | The idea is that you can have several project sharing the same output 35 | directory. In that case they will also share references and use searches will 36 | work between them. 37 | 38 | Install via Arch User Repository (AUR) 39 | ====================================== 40 | 41 | Execute these commands in Arch Linux: 42 | ```bash 43 | git clone https://aur.archlinux.org/woboq_codebrowser-git.git 44 | cd woboq_codebrowser-git 45 | makepkg -si 46 | ``` 47 | 48 | 49 | Compiling the generator on Linux 50 | ================================ 51 | 52 | LLVM+Clang version 16 or higher is required to build the generator. 53 | 54 | Example: 55 | ```bash 56 | mkdir build && cd build 57 | cmake -DCMAKE_BUILD_TYPE=Release .. 58 | make 59 | ``` 60 | 61 | Compiling the generator on macOS 62 | ============================================== 63 | 64 | Install XCode and then the command line tools: 65 | ```bash 66 | xcode-select --install 67 | ``` 68 | 69 | Install the clang libraries via [homebrew](http://brew.sh/): 70 | ```bash 71 | brew install llvm --with-clang --rtti 72 | ``` 73 | 74 | Then compile the generator: 75 | ```bash 76 | cmake . -DCMAKE_PREFIX_PATH=/usr/local/Cellar/llvm/ -DCMAKE_BUILD_TYPE=Release 77 | make 78 | ``` 79 | 80 | Using the generator 81 | =================== 82 | 83 | ### Step 1: Generate the compile_commands.json (see chapter "Compilation Database" below) for your project 84 | 85 | The code browser is built around the clang tooling infrastructure that uses compile_commands.json 86 | http://clang.llvm.org/docs/JSONCompilationDatabase.html 87 | 88 | See the section "Compilation Database (compile_commands.json)" below. 89 | 90 | ### Step 2: Create code HTML using codebrowser_generator 91 | 92 | Before generating, make sure the output directory is empty or does not contains 93 | stale files from a previous generation. 94 | 95 | Call the `codebrowser_generator`. See later for argument specification 96 | 97 | ### Step 3: Generate the directory index HTML files using codebrowser_indexgenerator 98 | 99 | By running the `codebrowser_indexgenerator` with the output directory as an argument 100 | 101 | ### Step 4: Copy the static data/ directory one level above the generated html 102 | 103 | ### Step 5: Open it in a browser or upload it to your webserver 104 | 105 | **Note**: By default, browsers do not allow AJAX on `file://` for security reasons. 106 | You need to upload the output directory on a web server, or serve your files with a local apache or nginx server. 107 | Alternatively, you can disable that security in Firefox by setting `security.fileuri.strict_origin_policy` to `false` in about:config (http://kb.mozillazine.org/Security.fileuri.strict_origin_policy) or start Chrome with the [--allow-file-access-from-files](http://www.chrome-allow-file-access-from-file.com/) option. 108 | 109 | Full usage example 110 | ================== 111 | 112 | Let's be meta in this example and try to generate the HTML files for the code browser itself. 113 | Assuming you are in the cloned directory: 114 | 115 | ```bash 116 | OUTPUT_DIRECTORY=~/public_html/codebrowser 117 | DATA_DIRECTORY=$OUTPUT_DIRECTORY/../data 118 | BUILD_DIRECTORY=$PWD 119 | SOURCE_DIRECTORY=$PWD 120 | VERSION=`git describe --always --tags` 121 | cmake . -DCMAKE_EXPORT_COMPILE_COMMANDS=ON 122 | ./generator/codebrowser_generator -b $BUILD_DIRECTORY -a -o $OUTPUT_DIRECTORY -p codebrowser:$SOURCE_DIRECTORY:$VERSION 123 | ./indexgenerator/codebrowser_indexgenerator $OUTPUT_DIRECTORY 124 | cp -rv ./data $DATA_DIRECTORY 125 | ``` 126 | 127 | You can adjust the variables and try similar commands to generate other projects. 128 | 129 | 130 | Arguments to codebrowser_generator 131 | ================================== 132 | 133 | Compiles sources into HTML files 134 | 135 | ```bash 136 | codebrowser_generator -a -o -b -p :[:] [-d ] [-e ::] 137 | ``` 138 | 139 | - `-a` process all files from the compile_commands.json. If this argument is not 140 | passed, the list of files to process need to be passed 141 | - `-o` with the output directory where the generated files will be put 142 | - `-b` the "build directory" containing the compile_commands.json If this argument 143 | is not passed, the compilation arguments can be passed on the command line 144 | after `--` 145 | - `-p` (one or more) with project specification. That is the name of the project, 146 | the absolute path of the source code, and the revision separated by colons 147 | example: `-p projectname:/path/to/source/code:0.3beta` 148 | - `-d` specify the data url where all the javascript and css files are found. 149 | default to ../data relative to the output dir 150 | example: `-d https://codebrowser.dev/data/`` 151 | - `-e` reference to an external project. 152 | example:`-e clang/include/clang:/opt/llvm/include/clang/:https://codebrowser.dev/llvm` 153 | 154 | 155 | Arguments to codebrowser_indexgenerator 156 | ======================================= 157 | 158 | Generates index HTML files for each directory for the generated HTML files 159 | 160 | ```bash 161 | codebrowser_indexgenerator [-d data_url] [-p project_definition] 162 | ``` 163 | 164 | - `-p` (one or more) with project specification. That is the name of the project, 165 | the absolute path of the source code, and the revision separated by colons 166 | example: `-p projectname:/path/to/source/code:0.3beta` 167 | - `-d` specify the data url where all the javascript and css files are found. 168 | default to ../data relative to the output dir 169 | example: `-d https://codebrowser.dev/data/` 170 | 171 | 172 | Compilation Database (compile_commands.json) 173 | ============================================ 174 | The generator is a tool which uses clang's LibTooling. It needs either a 175 | compile_commands.json or the arguments to be passed after '--' if they are 176 | the same for every file. 177 | 178 | To generate the compile_commands.json: 179 | * For cmake, pass `-DCMAKE_EXPORT_COMPILE_COMMANDS=ON` as a cmake parameter 180 | * For qmake, configure/autoconf and others, follow the instructions in `scripts/fake_compiler.sh` or `scripts/woboq_cc.js`. 181 | These are fake compilers that append the compiler invocation to the json file and forward to the real compiler. 182 | Your real compiler is overriden using the CC/CXX environment variables 183 | Make sure to have the json file properly terminated. 184 | * If you use ninja, you can use `ninja -t compdb` 185 | * If you use qbs, you can use `qbs generate --generator clangdb` 186 | * There is also a project called Build EAR [Bear](https://github.com/rizsotto/Bear) that achieves a similar thing as our fake compilers 187 | but is using `LD_PRELOAD` to inject itself into the build process to catch how the compiler is invoked. 188 | 189 | 190 | There is also some further information on https://sarcasm.github.io/notes/dev/compilation-database.html#clang 191 | 192 | 193 | Getting help 194 | ============ 195 | No matter if you are a licensee or are just curious and evaulating, we'd love to help you. 196 | Ask us via e-mail on info@kdab.com 197 | 198 | If you find a bug or incompatibility, please file a github issue: 199 | https://github.com/kdab/codebrowser/issues 200 | 201 | 202 | Licence information 203 | ==================== 204 | Licensees holding valid commercial licenses provided by Woboq may use 205 | this software in accordance with the terms contained in a written agreement 206 | between the licensee and Woboq. 207 | 208 | Alternatively, this work may be used under a Creative Commons 209 | Attribution-NonCommercial-ShareAlike 3.0 (CC-BY-NC-SA 3.0) License. 210 | http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US 211 | 212 | This license does not allow you to use the code browser to assist the 213 | development of your commercial software. If you intent to do so, consider 214 | purchasing a commercial licence. 215 | -------------------------------------------------------------------------------- /data/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDAB/codebrowser/9c819d5072dba9ba8eb07646d712b46229f7ecb5/data/back.png -------------------------------------------------------------------------------- /data/common.css: -------------------------------------------------------------------------------- 1 | @import "jquery/jquery-ui.css"; 2 | 3 | /* layout */ 4 | body { color:#000000; background-color:#ffffff; padding:0; margin: 0; font-family: Helvetica,sans-serif; } 5 | a { color: #037; border: none; text-decoration: none } 6 | a:hover{ text-decoration: underline } 7 | 8 | div#header { position:fixed; top:0; left:0; right:0; background-color: #f5f5f5; z-index:2; height: 5.2em; overflow: clip; } 9 | div#header+hr {position:fixed; top:5.2em; left:0; right:0; z-index:2} 10 | div#header input {-webkit-appearance:searchfield;-moz-appearance:searchfield;appearance:searchfield;} 11 | div#content { margin-top: 5.3em; } 12 | 13 | /* Fixme: We could experiment around with max-height: 90 vh? */ 14 | #allSideBoxes { 15 | position:fixed; margin-top:1ex; top:5.2em; right:10px; z-index:1; 16 | max-height:30em; 17 | } 18 | .sideBox { 19 | padding:1ex; border-radius:0.5ex; overflow:hide; font-size:smaller; margin-bottom:1em; 20 | max-height:100%; 21 | } 22 | .sideBox h3 { text-align:center; width:100%; cursor: pointer; cursor: hand; margin: 0;} 23 | .sideBox ul { 24 | display:block; overflow:auto; max-width:20em; max-height:20em; list-style:none; margin: 0; padding: 1em; 25 | } 26 | .sideBox li { 27 | list-style-type: none; padding: 0; margin-right: 1ex; 28 | } 29 | 30 | .code { border-collapse:collapse; width:100%; padding:0 } 31 | .code { font-family: monospace; } 32 | table.code{ table-layout:fixed; width: 100% } /* This improves performence. The idea is that the second column just overflows */ 33 | .code th { width:6.5ex; padding-right:1ex; background-color:#eeeeee ; 34 | text-align:right; color:black; font-weight:normal; 35 | -moz-user-select: none; user-select: none; } 36 | .code td { padding-left: 1ex; white-space: pre } 37 | 38 | #footer { font-size: smaller; margin:1ex; color: #333; text-align: right } 39 | #footer img { vertical-align: middle; } 40 | img { border: none; } 41 | input#searchline { margin: 1ex; width: 30em; max-width: 50%; } 42 | #breadcrumb { padding:0; margin: 0 1ex 2ex 1ex; font-size:inherit; font-weight: normal } 43 | hr { margin: 0; border-collapse:collapse; background-color: #e5e5e5; height:1px;border:none; } 44 | p#options { font-size: small; position: absolute; right:1ex; top:48px; margin: 0 1ex 0 0 } 45 | a.logo { float:right } 46 | #breadcrumb_symbol a { color:inherit } 47 | 48 | #tooltip { 49 | position:absolute; 50 | display:none; 51 | padding:1em; 52 | padding-top:1ex; 53 | border: 1px solid gray; 54 | background-color: white; 55 | font-size: smaller; 56 | opacity: 0.9; 57 | border-radius: 4px; 58 | max-width: 80%; 59 | box-shadow:1px 1px 7px gray; 60 | z-index:2; 61 | } 62 | #tooltip ul { margin:0; padding-left: 1em } 63 | #tooltip a.showuse {color:inherit; text-decoration:underline} 64 | #tooltip b a { color:inherit } 65 | #tooltip abbr { cursor: help; border-bottom: 1px dashed #000; } 66 | /*#tooltip li { border: 1px solid blue; margin:0 }*/ 67 | 68 | p.warnmsg { color: #a00; padding: 0 1ex; margin: 0.3ex 0; } 69 | 70 | .code a { text-decoration:none; color:inherit } 71 | .code a:hover { text-decoration: none } 72 | 73 | .error { border-bottom: 1px dashed red } 74 | .warning { border-bottom: 1px dotted #c90; } 75 | 76 | #tooltip i { color: #888; white-space: pre-wrap; font-family: monospace } 77 | #tooltip .ppcond { color: #063; white-space: pre-wrap; font-family: monospace; font-weight:bold } 78 | #tooltip .ppcond a { font-weight: normal; color:inherit } 79 | 80 | /* disable the keywords in strings (macro have that) */ 81 | .code .string em, .code .string b, .code .string var { color:inherit; font-style:inherit; font-weight:inherit; } 82 | 83 | /* Old Macro expansions.*/ 84 | .expansion { display: none; } 85 | 86 | .fake { display: inline-block; position:relative; bottom: 0.7em; opacity: 0.8; font-size:small } 87 | .fake::before { content: "\2380"; } 88 | .refarg::before { display: inline-block; position:relative; bottom: 0.7em; 89 | opacity: 0.8; font-size:x-small; color: gray; content: "&"; } 90 | 91 | @media only screen and (max-width: 30em) { 92 | .code {font-size: smaller;} 93 | p#options {display:none;} 94 | #breadcrumb span { display:none; } 95 | /* This makes sure that there is no horizontal scrollbar on mobile. 96 | Mobile users can use tab to scroll, and google does not consider we are mobile-ready otherwise */ 97 | div#content { overflow-x:auto; } 98 | } 99 | @media only screen and (max-width: 60em) { 100 | #allSideBoxes { display: none;} 101 | .inlayHint { 102 | font-size: smaller; 103 | border-radius: 3px; 104 | border: 1px solid #d9d9d9; 105 | -webkit-user-select: none; /* Safari */ 106 | -moz-user-select: none; /* Firefox */ 107 | -ms-user-select: none; /* IE10+/Edge */ 108 | user-select: none; /* Standard */ 109 | } 110 | -------------------------------------------------------------------------------- /data/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDAB/codebrowser/9c819d5072dba9ba8eb07646d712b46229f7ecb5/data/folder.png -------------------------------------------------------------------------------- /data/indexscript.js: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright (C) 2012-2016 Woboq GmbH 3 | * Olivier Goffart 4 | * https://woboq.com/codebrowser.html 5 | * 6 | * This file is part of the Woboq Code Browser. 7 | * 8 | * Commercial License Usage: 9 | * Licensees holding valid commercial licenses provided by Woboq may use 10 | * this file in accordance with the terms contained in a written agreement 11 | * between the licensee and Woboq. 12 | * For further information see https://woboq.com/codebrowser.html 13 | * 14 | * Alternatively, this work may be used under a Creative Commons 15 | * Attribution-NonCommercial-ShareAlike 3.0 (CC-BY-NC-SA 3.0) License. 16 | * http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US 17 | * This license does not allow you to use the code browser to assist the 18 | * development of your commercial software. If you intent to do so, consider 19 | * purchasing a commercial licence. 20 | ****************************************************************************/ 21 | 22 | 23 | $(function() { 24 | // ATTENTION: Keep in sync with C++ function of the same name in filesystem.cpp and `Generator::escapeAttrForFilename` 25 | var replace_invalid_filename_chars = function (str) { 26 | if(window.ecma_script_api_version && window.ecma_script_api_version >= 2) { 27 | return str.replace(new RegExp(':', 'g'), '.'); 28 | } 29 | 30 | return str; 31 | } 32 | 33 | // remove trailing slash 34 | root_path = root_path.replace(/\/$/, ""); 35 | if(!root_path) root_path = "."; 36 | 37 | 38 | //compute the length of the common prefix between two strings 39 | // (copied from codebrowser.js) 40 | var prefixLen = function( s1 , s2) { 41 | var maxMatchLen = Math.min(s1.length, s2.length); 42 | var res = -1; 43 | while (++res < maxMatchLen) { 44 | if (s1.charAt(res) != s2.charAt(res)) 45 | break; 46 | } 47 | return res * 256 + 256 - s1.length; 48 | } 49 | 50 | // Google text search (different than codebrowser.js) 51 | var text_search = function(text) { 52 | var location = "" + (window.location); 53 | window.location = "http://google.com/search?sitesearch=" + encodeURIComponent(location) + "&q=" + encodeURIComponent(text); 54 | } 55 | 56 | var fileIndex = []; 57 | var searchTerms = {} 58 | var functionDict = {}; 59 | var file = path; 60 | 61 | var searchline = $("input#searchline"); 62 | 63 | //BEGIN copied from codebrowser.js 64 | 65 | // callback for jqueryui's autocomple activate 66 | var activate = function(event,ui) { 67 | var val = ui.item.value; 68 | var type = searchTerms[val] && searchTerms[val].type; 69 | if (type == "file") { 70 | window.location = root_path + '/' + searchTerms[val].file + ".html"; 71 | } else if (type == "ref") { 72 | var ref = searchTerms[val].ref; 73 | var url = root_path + "/refs/" + replace_invalid_filename_chars(ref); 74 | $.get(url, function(data) { 75 | var res = $(""+data+""); 76 | var def = res.find("def"); 77 | var result = { len: -1 }; 78 | def.each( function() { 79 | var cur = { len : -1, 80 | f : $(this).attr("f"), 81 | l : $(this).attr("l") } 82 | 83 | cur.len = prefixLen(cur.f, file) 84 | if (cur.len >= result.len) { 85 | result = cur; 86 | result.isMarcro = ($(this).attr("macro")); 87 | } 88 | }); 89 | 90 | if (result.len >= 0) { 91 | var newloc = root_path + "/" + result.f + ".html#" + 92 | (result.isMarcro ? result.l : ref ); 93 | window.location = newloc; 94 | } 95 | }); 96 | } else { 97 | text_search(val); 98 | } 99 | }; 100 | 101 | var getFnNameKey = function (request) { 102 | if (request.indexOf('/') != -1 || request.indexOf('.') != -1) 103 | return false; 104 | var mx = request.match(/::([^:]{2})[^:]*$/); 105 | if (mx) 106 | return mx[1].toLowerCase().replace(/[^a-z]/, '_'); 107 | request = request.replace(/^:*/, ""); 108 | if (request.length < 2) 109 | return false; 110 | var k = request.substr(0, 2).toLowerCase(); 111 | return k.replace(/[^a-z]/, '_') 112 | } 113 | 114 | var autocomplete = function(request, response) { 115 | var term = $.ui.autocomplete.escapeRegex(request.term); 116 | var rx1 = new RegExp(term, 'i'); 117 | var rx2 = new RegExp("(^|::)"+term.replace(/^:*/, ''), 'i'); 118 | var functionList = []; 119 | var k = getFnNameKey(request.term) 120 | if (k && Object.prototype.hasOwnProperty.call(functionDict,k)) { 121 | functionList = functionDict[k].filter( 122 | function(word) { return word.match(rx2) }); 123 | } 124 | var l = fileIndex.filter( function(word) { return word.match(rx1); }); 125 | l = l.concat(functionList); 126 | l = l.slice(0,1000); // too big lists are too slow 127 | response(l); 128 | }; 129 | 130 | searchline.autocomplete( {source: autocomplete, select: activate, minLength: 4 } ); 131 | 132 | searchline.keypress(function(e) { 133 | var value = searchline.val(); 134 | if(e.which == 13) { 135 | activate({}, { item: { value: value } }); 136 | } 137 | }); 138 | 139 | // When the content changes, fetch the list of function that starts with ... 140 | searchline.on('input', function() { 141 | var value = $(this).val(); 142 | var k = getFnNameKey(value); 143 | if (k && !Object.prototype.hasOwnProperty.call(functionDict, k)) { 144 | functionDict[k] = [] 145 | $.get(root_path + '/fnSearch/' + k, function(data) { 146 | var list = data.split("\n"); 147 | for (var i = 0; i < list.length; ++i) { 148 | var sep = list[i].indexOf('|'); 149 | var ref = list[i].slice(0, sep); 150 | var name = list[i].slice(sep+1); 151 | searchTerms[name] = { type:"ref", ref: ref }; 152 | functionDict[k].push(name); 153 | } 154 | if (searchline.is(":focus")) { 155 | searchline.autocomplete("search", searchline.val()); 156 | } 157 | }); 158 | } 159 | }); 160 | 161 | // Pasting should show the autocompletion 162 | searchline.on("paste", function() { setTimeout(function() { 163 | searchline.autocomplete("search", searchline.val()); 164 | }, 0); 165 | }); 166 | 167 | //END copied from codebrowser.js 168 | 169 | 170 | $.get(root_path + '/fileIndex', function(data) { 171 | var list = data.split("\n"); 172 | list.sort(); 173 | 174 | fileIndex = list; 175 | for (var i = 0; i < list.length; ++i) { 176 | searchTerms[list[i]] = { type:"file", file: list[i] }; 177 | } 178 | 179 | 180 | function openFolder() { 181 | var t = $(this); 182 | var state = {}; 183 | if (history) 184 | state = history.state || state; 185 | if (!this._opened) { 186 | this._opened = true; 187 | var p = t.attr("data-path") + "/"; 188 | var subPath = path=="" ? p : p.substr(path.length); 189 | t.text("[-]"); 190 | var content = $(""); 191 | var dict = {}; 192 | var toOpenNow = []; 193 | for (var i=0; i < fileIndex.length; ++i) { 194 | var f = fileIndex[i]; 195 | if (f.indexOf(p) == 0) { 196 | var sl = f.indexOf('/', p.length + 1); 197 | 198 | if (sl !== -1) { 199 | var name = f.substr( p.length, sl - p.length); 200 | if (dict[name]) 201 | continue; 202 | dict[name] = true; 203 | content.append("\n"); 205 | if (state[p+name]) 206 | toOpenNow.push(p+name); 207 | } else { 208 | var name = f.substr(p.length); 209 | content.append("\n"); 210 | } 211 | } 212 | } 213 | content.find(".opener").click(openFolder); 214 | t.parent().append(content); 215 | state[t.attr("data-path")]=true; 216 | toOpenNow.forEach(function(toOpen) { 217 | var e = $("a[data-path='"+toOpen+"']").get(0) 218 | if (e) 219 | openFolder.call(e); 220 | }); 221 | } else { 222 | t.parent().find("> table").empty(); 223 | t.text("[+]"); 224 | this._opened = false; 225 | state[t.attr("data-path")]=false; 226 | } 227 | if (history && history.replaceState) 228 | history.replaceState(state, undefined); 229 | return false; 230 | } 231 | 232 | $(".opener").click(openFolder); 233 | var state; 234 | if (history) 235 | state = history.state; 236 | if (state) { 237 | $(".opener").each(function(e) { 238 | if (state[$(this).attr("data-path")]) 239 | openFolder.call(this); 240 | }); 241 | } 242 | }); 243 | 244 | $("#footer").before("

What is this ?

This is an online code browser that allows you to browse C/C++ code just like in your IDE, " 245 | + "with semantic highlighting and contextual tooltips that show you the usages and cross references.
" 246 | + "Open a C or C++ file and try it by hovering over the symbols!
" 247 | + "Or take the feature tour." 248 | + "

") 249 | }); 250 | 251 | -------------------------------------------------------------------------------- /data/indexstyle.css: -------------------------------------------------------------------------------- 1 | @import "jquery/jquery-ui.css"; 2 | 3 | body { color:#000000; background-color:#ffffff; padding:0; margin: 0; font-family: Helvetica,sans-serif; } 4 | a { color: #037; border: none; text-decoration: none } 5 | a:visited { color: #737; } 6 | a:hover{ text-decoration: underline } 7 | #footer { font-size: smaller; margin:1ex; color: #333; text-align: right } 8 | #footer img { vertical-align: middle; } 9 | #whatisit { max-width: 30em; margin: auto; padding:1ex; } 10 | img { border: none; } 11 | input#searchline { margin: 1ex; width: 30em; max-width: 50%; } 12 | @media only screen and (max-width: 30em) { 13 | input#searchline {max-width: 90%; } 14 | } 15 | p { margin:0 } 16 | 17 | /* 1.9 logo, we keep this for compatibility for a common data/ directory */ 18 | h1 { float: right; padding: 0px; margin:1px; 19 | background-image: url(woboq-48.png); background-repeat: no-repeat; 20 | height:48px; width: 126px; overflow:hidden 21 | } 22 | h1 a { visibility:hidden } 23 | 24 | h2 { font-size:medium; font-weight: normal; 25 | padding:0; margin: 0 1ex 2ex 1ex; } 26 | /* end compatibility */ 27 | div#toprightlogo { 28 | float: right; padding: 0px; margin:1px; 29 | background-image: url(woboq-48.png); background-repeat: no-repeat; 30 | height:48px; width: 126px; overflow:hidden 31 | } 32 | @media only screen and (max-width: 30em) { 33 | div#toprightlogo {display:block;float:none; margin:1em auto; padding: 0} 34 | } 35 | /* new h1 breadcrumb: */ 36 | h1#title { float: none; background-image: none; height:auto;width:auto; font-size:1em; 37 | font-weight:normal; margin-left:1ex;} 38 | h1#title a { visibility: visible } 39 | 40 | 41 | a { text-decoration:none} 42 | 43 | div#header { width:100%; background-color: #f5f5f5; min-height:5.2em; display:block;} 44 | div#header input {-webkit-appearance:searchfield;-moz-appearance:searchfield;appearance:searchfield;} 45 | 46 | hr { margin: 0; border-collapse:collapse;background-color: #e5e5e5; height:1px;border:none; } 47 | 48 | table#tree { padding: 1ex 1ex; } 49 | table#tree { text-align:left; margin: auto} 50 | 51 | 52 | table#tree table { padding:0; padding-left: 4ex; margin:0; border:0; } 53 | table#tree td { white-space: pre; font-family:monospace; margin:0; padding:0; border: 0 } 54 | table#tree tr { margin:0; border:0; padding:0 } 55 | 56 | table#tree tr:nth-child(even) { background-color: #fafafa } 57 | table#tree tr table { background-color: white } 58 | 59 | /* 60 | table#tree tr:hover { background-color: #eee } 61 | table#tree tr:hover table { background-color: white }*/ 62 | 63 | td a { padding: 1px; } 64 | td.folder > a { padding-left: 22px; background: url("folder.png") no-repeat left } 65 | td.file > a { padding-left: 22px; background: url("txt.png") no-repeat left } 66 | td.parent > a { padding-left: 22px; background: url("back.png") no-repeat left } 67 | 68 | td a.opener { color:inherit; background: none; padding:0 } 69 | 70 | /* class list */ 71 | td span.meta { white-space:pre-line;display:inline ; float:right;} 72 | td span.meta a { } 73 | td span.meta ul { margin: 0; padding:0; display:inline ;} 74 | td span.meta ul li { list-style-type: none; padding:0; margin:0;padding-left:1ex; } 75 | 76 | /* Hide [+], make more list-ish */ 77 | @media only screen and (max-width: 30em) { 78 | table#tree td { white-space: pre-line; } 79 | td a.opener { display : none; } 80 | td span.meta { display: block; float: none;} 81 | td > a { margin-bottom: 1em !important; display:block;} 82 | td span.meta ul li { margin-bottom: 1em ; } 83 | } 84 | -------------------------------------------------------------------------------- /data/jquery/images/ui-bg_diagonals-thick_18_b81900_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDAB/codebrowser/9c819d5072dba9ba8eb07646d712b46229f7ecb5/data/jquery/images/ui-bg_diagonals-thick_18_b81900_40x40.png -------------------------------------------------------------------------------- /data/jquery/images/ui-bg_diagonals-thick_20_666666_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDAB/codebrowser/9c819d5072dba9ba8eb07646d712b46229f7ecb5/data/jquery/images/ui-bg_diagonals-thick_20_666666_40x40.png -------------------------------------------------------------------------------- /data/jquery/images/ui-bg_glass_100_f6f6f6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDAB/codebrowser/9c819d5072dba9ba8eb07646d712b46229f7ecb5/data/jquery/images/ui-bg_glass_100_f6f6f6_1x400.png -------------------------------------------------------------------------------- /data/jquery/images/ui-bg_glass_100_fdf5ce_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDAB/codebrowser/9c819d5072dba9ba8eb07646d712b46229f7ecb5/data/jquery/images/ui-bg_glass_100_fdf5ce_1x400.png -------------------------------------------------------------------------------- /data/jquery/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDAB/codebrowser/9c819d5072dba9ba8eb07646d712b46229f7ecb5/data/jquery/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /data/jquery/images/ui-bg_gloss-wave_35_f6a828_500x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDAB/codebrowser/9c819d5072dba9ba8eb07646d712b46229f7ecb5/data/jquery/images/ui-bg_gloss-wave_35_f6a828_500x100.png -------------------------------------------------------------------------------- /data/jquery/images/ui-bg_highlight-soft_100_eeeeee_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDAB/codebrowser/9c819d5072dba9ba8eb07646d712b46229f7ecb5/data/jquery/images/ui-bg_highlight-soft_100_eeeeee_1x100.png -------------------------------------------------------------------------------- /data/jquery/images/ui-bg_highlight-soft_75_ffe45c_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDAB/codebrowser/9c819d5072dba9ba8eb07646d712b46229f7ecb5/data/jquery/images/ui-bg_highlight-soft_75_ffe45c_1x100.png -------------------------------------------------------------------------------- /data/jquery/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDAB/codebrowser/9c819d5072dba9ba8eb07646d712b46229f7ecb5/data/jquery/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /data/jquery/images/ui-icons_228ef1_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDAB/codebrowser/9c819d5072dba9ba8eb07646d712b46229f7ecb5/data/jquery/images/ui-icons_228ef1_256x240.png -------------------------------------------------------------------------------- /data/jquery/images/ui-icons_ef8c08_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDAB/codebrowser/9c819d5072dba9ba8eb07646d712b46229f7ecb5/data/jquery/images/ui-icons_ef8c08_256x240.png -------------------------------------------------------------------------------- /data/jquery/images/ui-icons_ffd27a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDAB/codebrowser/9c819d5072dba9ba8eb07646d712b46229f7ecb5/data/jquery/images/ui-icons_ffd27a_256x240.png -------------------------------------------------------------------------------- /data/jquery/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDAB/codebrowser/9c819d5072dba9ba8eb07646d712b46229f7ecb5/data/jquery/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /data/jquery/jquery-ui.css: -------------------------------------------------------------------------------- 1 | /*! jQuery UI - v1.11.4 - 2016-05-27 2 | * http://jqueryui.com 3 | * Includes: core.css, autocomplete.css, menu.css, theme.css 4 | * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS%2CTahoma%2CVerdana%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=gloss_wave&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=highlight_soft&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=glass&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=glass&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=highlight_soft&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=diagonals_thick&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=diagonals_thick&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=flat&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px 5 | * Copyright jQuery Foundation and other contributors; Licensed MIT */ 6 | 7 | .ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:none}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{position:relative;margin:0;padding:3px 1em 3px .4em;cursor:pointer;min-height:0;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-widget{font-family:Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #ddd;background:#eee url("images/ui-bg_highlight-soft_100_eeeeee_1x100.png") 50% top repeat-x;color:#333}.ui-widget-content a{color:#333}.ui-widget-header{border:1px solid #e78f08;background:#f6a828 url("images/ui-bg_gloss-wave_35_f6a828_500x100.png") 50% 50% repeat-x;color:#fff;font-weight:bold}.ui-widget-header a{color:#fff}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #ccc;background:#f6f6f6 url("images/ui-bg_glass_100_f6f6f6_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#1c94c4}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#1c94c4;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #fbcb09;background:#fdf5ce url("images/ui-bg_glass_100_fdf5ce_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#c77405}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited{color:#c77405;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #fbd850;background:#fff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#eb8f00}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#eb8f00;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fed22f;background:#ffe45c url("images/ui-bg_highlight-soft_75_ffe45c_1x100.png") 50% top repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#b81900 url("images/ui-bg_diagonals-thick_18_b81900_40x40.png") 50% 50% repeat;color:#fff}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#fff}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#fff}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_222222_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-default .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-state-active .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-state-highlight .ui-icon{background-image:url("images/ui-icons_228ef1_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_ffd27a_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:4px}.ui-widget-overlay{background:#666 url("images/ui-bg_diagonals-thick_20_666666_40x40.png") 50% 50% repeat;opacity:.5;filter:Alpha(Opacity=50)}.ui-widget-shadow{margin:-5px 0 0 -5px;padding:5px;background:#000;opacity:.2;filter:Alpha(Opacity=20);border-radius:5px} -------------------------------------------------------------------------------- /data/kdevelop.css: -------------------------------------------------------------------------------- 1 | @import "common.css"; 2 | 3 | /* color style */ 4 | /*.comment, */ .code i { color: #888; font-style: oblique } 5 | .code i.doc { color: #00f; font-style: oblique } 6 | .code i .command { color: #CA60CA; font-weight: bold; font-style: normal;} 7 | .code i .arg { color: #0095FF; font-weight: bold; font-style: normal;} 8 | .code i .tag { color: #000; font-weight: bold; font-style: normal;} 9 | .code i .verb { color: #888; } 10 | .code i .command + .verb, .code i .command + a .verb { color: #f00; font-style:normal } 11 | .code i a { color: #037; } 12 | /*.keyword, */ .code b { font-weight: bold; } 13 | /*.keytype, */ .code em { color: #0057AE; font-style:normal } 14 | .code .string, .code q { color: #BF0303; font-style: normal } 15 | .code q::before , .code q::after { content:none; } 16 | /*.directive,*/ .code u { color: #063; text-decoration:none; } 17 | /*.num, */ .code var { color: #B08000; font-style: normal; } 18 | /*.char, */ .code kdb, .code kbd { color: #FF80E0 } 19 | 20 | /* code a, code dfn */ 21 | .code .ref { color: #208 } 22 | .code .type , #tooltip .type { color: #061 } 23 | .code .typedef { color: #35938D } 24 | .code .member { color: #B08000 } 25 | .code .call { color: #207 } 26 | .code .namespace, .code .enum { color: #862a38 } 27 | .code .decl { color: #205; font-weight:bold; } 28 | .code .macro { background-color:#efe; color: inherit; } 29 | .code .macro:hover { background-color:#BEFF9B; } 30 | .code .macro.highlight { background-color:#BEFF9B !important; } 31 | 32 | .code .col0 {color:#2400FF} .code .col1 {color:#9C00FF} .code .col2 {color:#D1008A} .code .col3 {color:#FF0000} .code .col4 {color:#FF4F00} 33 | .code .col5 {color:#F69D00} .code .col6 {color:#72D200} .code .col7 {color:#00F718} .code .col8 {color:#00BBCD} .code .col9 {color:#0053FF} 34 | 35 | .code dfn { font-style:normal } 36 | .code .virtual { font-style: italic; } 37 | 38 | .highlight { background-color: #FBFA96 !important; color: black !important;} 39 | th.highlight { font-weight: bold; } 40 | th.highlight+td { background-color: #f8f7f6; } 41 | 42 | .sideBox { border: 1px solid #ddd; background-color: #eee; } 43 | -------------------------------------------------------------------------------- /data/qtcreator.css: -------------------------------------------------------------------------------- 1 | @import "common.css"; 2 | 3 | /* color style */ 4 | .code q::before , .code q::after { content:none; } 5 | .code dfn { font-style: normal } 6 | 7 | .code b, .code em { color: #808000; font-style:normal; font-weight: normal} 8 | .code i, .code q, .code kbd, .code kdb, .code u>a, .code .string { color: #008000 ; font-style:normal; font-weight: normal} 9 | .code i.doc { color: #000080; } 10 | .code i .command { color: #00f } 11 | .code i a { color: #037; } 12 | .code var, .code u, .code .macro { color: #000080; text-decoration: none; font-style:normal } 13 | 14 | .code .type, .code .typedef, .code .namespace, .code .enum { color: #800080} 15 | .code .field, .code .member, .code .lbl { color: #860d0d } 16 | .code .virtual { font-style: italic } 17 | .code .local { color: #092e64 } 18 | .code .lbl { color: #800000 } 19 | .code .global { color: #ce5c00 } /* FIXME */ 20 | .code .fn { color: #00677c } 21 | 22 | 23 | .highlight { background-color: #eee; border-radius:3px; border: 1px solid #B4B4B4; margin:-1px} 24 | th.highlight { font-weight: bold; } 25 | th.highlight+td { background-color: #eee; } 26 | 27 | .sideBox { border: 1px solid #ddd; background-color: #eee; } 28 | 29 | -------------------------------------------------------------------------------- /data/solarized.css: -------------------------------------------------------------------------------- 1 | @import "common.css"; 2 | 3 | .code { font-family: DejaVu sans Mono , monospace; } 4 | h1#breadcrumb span { display:none } 5 | hr { margin: 0; border-collapse:collapse; background-color: #e5e5e5; height:1px;border:none;} 6 | p.warnmsg { color: #D44; padding: 0 1ex; margin: 0.5ex 0; } 7 | .code th a { color: inherit } 8 | 9 | 10 | body, table.code, input, select, div#header, div#header + hr { background-color: #002b36; color: #839496;} 11 | h1, h3, h2 { color: #93a1a1; } 12 | 13 | .code th { background-color: #073642; color: #93a1a1; } 14 | a { color: #93a1a1; } 15 | #tooltip { background-color: #073642; color: #93a1a1 } 16 | #tooltip a { color: #6c71c4;} 17 | hr { border: 1px solid #073642 } 18 | input { background-color: #002b36 } 19 | #footer { color: #839496; } 20 | #header img { display:none } 21 | 22 | /* 23 | $base03: #002b36; 24 | $base02: #073642; 25 | $base01: #586e75; 26 | $base00: #657b83; 27 | $base0: #839496; 28 | $base1: #93a1a1; 29 | $base2: #eee8d5; 30 | $base3: #fdf6e3; 31 | $yellow: #b58900; 32 | $orange: #cb4b16; 33 | $red: #dc322f; 34 | $magenta: #d33682; 35 | $violet: #6c71c4; 36 | $blue: #268bd2; 37 | $cyan: #2aa198; 38 | $green: #859900; 39 | */ 40 | 41 | /* color style */ 42 | /*.comment, */ .code i { color: #268bd2; font-style: oblique } 43 | /*.keyword, */ .code b { color: #859900; font-weight: bold; } 44 | /*.keytype, */ .code em { color: #b58900; font-weight:bold; font-style:normal } 45 | .code .string, .code q { color: #2aa198; font-style: normal } 46 | .code q::before , .code q::after { content:none; } 47 | /*.directive,*/ .code u { color: #dc322f; text-decoration:none; } 48 | /*.num, */ .code var { color: #2aa198; font-style: normal; } 49 | /*.char, */ .code kbd, .code kdb { color: #dc322f } 50 | 51 | /* code a, code dfn */ 52 | .code .ref, .code .decl { color:#93a1a1} 53 | .code .decl { font-weight:bold; } 54 | .namespace, .enum, .typedef { color: #6c71c4;} 55 | .code .type { color: #b58900;} 56 | .code .local { color: #d33682; } 57 | /*.typedef { color: #35938D }*/ 58 | .code .member { color: #cb4b16; } 59 | /*.call { color: #20f }*/ 60 | .macro { color: #d33682; } 61 | /*.macro:hover { background-color:#BEFF9B; }*/ 62 | /* 63 | .ref.col0 {color:#2400FF} .ref.col1 {color:#9C00FF} .ref.col2 {color:#D1008A} .ref.col3 {color:#FF0000} .ref.col4 {color:#FF4F00} 64 | .ref.col5 {color:#F69D00} .ref.col6 {color:#72D200} .ref.col7 {color:#00F718} .ref.col8 {color:#00BBCD} .ref.col9 {color:#0053FF} 65 | */ 66 | .code dfn { font-style:normal } 67 | .code .virtual { font-style: italic; } 68 | 69 | .highlight { background-color: #073642 !important; } 70 | th.highlight+td { background-color: #073642 !important; } 71 | 72 | .sideBox { background-color: #073642 !important; border: 1px solid #073642;} 73 | .inlayHint { 74 | border: 1px solid #839496; 75 | } 76 | -------------------------------------------------------------------------------- /data/txt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDAB/codebrowser/9c819d5072dba9ba8eb07646d712b46229f7ecb5/data/txt.png -------------------------------------------------------------------------------- /data/woboq-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDAB/codebrowser/9c819d5072dba9ba8eb07646d712b46229f7ecb5/data/woboq-48.png -------------------------------------------------------------------------------- /generator/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(codebrowser_generator) 3 | 4 | Find_Package(LLVM REQUIRED CONFIG) 5 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION} in ${LLVM_INSTALL_PREFIX}") 6 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") 7 | Find_Package(Clang REQUIRED CONFIG HINTS "${LLVM_INSTALL_PREFIX}/lib/cmake/clang") 8 | message(STATUS "Found Clang in ${CLANG_INSTALL_PREFIX}") 9 | 10 | add_executable(codebrowser_generator main.cpp projectmanager.cpp annotator.cpp generator.cpp preprocessorcallback.cpp 11 | filesystem.cpp qtsupport.cpp commenthandler.cpp ${CMAKE_CURRENT_BINARY_DIR}/projectmanager_systemprojects.cpp 12 | inlayhintannotator.cpp) 13 | target_include_directories(codebrowser_generator PRIVATE "${CMAKE_CURRENT_LIST_DIR}") 14 | 15 | target_link_libraries(codebrowser_generator PRIVATE clang-cpp) 16 | 17 | if(TARGET LLVM) 18 | target_link_libraries(codebrowser_generator PRIVATE LLVM) 19 | else() 20 | # We cannot use llvm_config() here because in some versions it uses PRIVATE when calling target_link_libraries 21 | # and in some it doesn't. If our calls of target_link_libraries don't do it the same way, we get a 22 | # fatal error. 23 | llvm_map_components_to_libnames(llvm_libs core support) 24 | target_link_libraries(codebrowser_generator PRIVATE ${llvm_libs}) 25 | endif() 26 | 27 | install(TARGETS codebrowser_generator RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) 28 | target_include_directories(codebrowser_generator SYSTEM PUBLIC ${CLANG_INCLUDE_DIRS}) 29 | set_property(TARGET codebrowser_generator PROPERTY CXX_STANDARD 20) 30 | 31 | 32 | if (NOT APPLE AND NOT MSVC) 33 | # Don't link with libs that overlaps our options 34 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed" ) 35 | endif() 36 | 37 | 38 | # System include dirs 39 | if(WIN32) 40 | message(STATUS "Adding the following dirs as system projects") 41 | foreach(dir $ENV{INCLUDE}) 42 | list(APPEND SYSTEM_INCLUDE_DIRS "include;${dir}") 43 | endforeach() 44 | else() 45 | list(APPEND SYSTEM_INCLUDE_DIRS "include;/usr/include/") 46 | endif() 47 | string(REPLACE "\\" "/" SYSTEM_INCLUDE_DIRS "${SYSTEM_INCLUDE_DIRS}") 48 | configure_file(projectmanager_systemprojects.cpp.in projectmanager_systemprojects.cpp) 49 | 50 | if(NOT MSVC) 51 | # Flags not supported by MSVC 52 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -fno-rtti") 53 | 54 | # TODO: Split up files and insert them row by row because 55 | # MSVC only accepts strings of 2^16 bytes length (~65kb) 56 | 57 | # Embed the clang header into the binary: 58 | string(REPLACE "svn" "" LLVM_VERSION "${LLVM_VERSION}") 59 | string(REGEX REPLACE "git.*$" "" LLVM_VERSION "${LLVM_VERSION}") 60 | if(NOT CLANG_BUILTIN_HEADERS_DIR) 61 | set(CLANG_BUILTIN_HEADERS_DIR "${LLVM_LIBRARY_DIR}/clang/${LLVM_VERSION}/include") 62 | endif() 63 | 64 | # try LLVM_VERSION_MAJOR, starting with llvm 16 the above fails 65 | if (NOT EXISTS ${CLANG_BUILTIN_HEADERS_DIR}) 66 | set(CLANG_BUILTIN_HEADERS_DIR "${LLVM_LIBRARY_DIR}/clang/${LLVM_VERSION_MAJOR}/include") 67 | endif() 68 | 69 | 70 | file(GLOB BUILTINS_HEADERS "${CLANG_BUILTIN_HEADERS_DIR}/*.h") 71 | if(NOT BUILTINS_HEADERS) 72 | message(FATAL_ERROR "Could not find any clang builtins headers in ${CLANG_BUILTIN_HEADERS_DIR}") 73 | endif() 74 | foreach(BUILTIN_HEADER ${BUILTINS_HEADERS}) 75 | #filter files that are way to big 76 | if(NOT BUILTIN_HEADER MATCHES ".*/(arm_neon.h|altivec.h|vecintrin.h|avx512.*intrin.h)") 77 | file(READ ${BUILTIN_HEADER} BINARY_DATA) 78 | string(REPLACE "\\" "\\\\" BINARY_DATA "${BINARY_DATA}") 79 | string(REPLACE "\"" "\\\"" BINARY_DATA "${BINARY_DATA}") 80 | string(REPLACE "\n" "\\n\"\n\"" BINARY_DATA "${BINARY_DATA}") 81 | #workaround the fact that stdint.h includes itself 82 | string(REPLACE "__CLANG_STDINT_H" "__CLANG_STDINT_H2" BINARY_DATA "${BINARY_DATA}") 83 | string(REPLACE "${CLANG_BUILTIN_HEADERS_DIR}/" "/builtins/" FN "${BUILTIN_HEADER}" ) 84 | set(EMBEDDED_DATA "${EMBEDDED_DATA} { \"${FN}\" , \"${BINARY_DATA}\" } , \n") 85 | endif() 86 | endforeach() 87 | endif() 88 | 89 | configure_file(embedded_includes.h.in embedded_includes.h) 90 | target_include_directories(codebrowser_generator PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) 91 | -------------------------------------------------------------------------------- /generator/annotator.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright (C) 2012-2016 Woboq GmbH 3 | * Olivier Goffart 4 | * https://woboq.com/codebrowser.html 5 | * 6 | * This file is part of the Woboq Code Browser. 7 | * 8 | * Commercial License Usage: 9 | * Licensees holding valid commercial licenses provided by Woboq may use 10 | * this file in accordance with the terms contained in a written agreement 11 | * between the licensee and Woboq. 12 | * For further information see https://woboq.com/codebrowser.html 13 | * 14 | * Alternatively, this work may be used under a Creative Commons 15 | * Attribution-NonCommercial-ShareAlike 3.0 (CC-BY-NC-SA 3.0) License. 16 | * http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US 17 | * This license does not allow you to use the code browser to assist the 18 | * development of your commercial software. If you intent to do so, consider 19 | * purchasing a commercial licence. 20 | ****************************************************************************/ 21 | 22 | #pragma once 23 | 24 | #include "commenthandler.h" 25 | #include "generator.h" 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | struct ProjectManager; 35 | struct ProjectInfo; 36 | class PreprocessorCallback; 37 | 38 | namespace clang { 39 | class Preprocessor; 40 | class NamedDecl; 41 | class MangleContext; 42 | class Type; 43 | class QualType; 44 | class Decl; 45 | class FileEntry; 46 | } 47 | 48 | /* Wrapper for the change in the name in clang 3.5 */ 49 | template 50 | auto getResultType(T *decl) -> decltype(decl->getResultType()) 51 | { 52 | return decl->getResultType(); 53 | } 54 | template 55 | auto getResultType(T *decl) -> decltype(decl->getReturnType()) 56 | { 57 | return decl->getReturnType(); 58 | } 59 | 60 | typedef std::pair pathTo_cache_key_t; 61 | namespace std { 62 | template<> 63 | struct hash 64 | { 65 | size_t operator()(const pathTo_cache_key_t &k) const noexcept 66 | { 67 | return k.first ^ k.second; 68 | } 69 | }; 70 | } 71 | 72 | class Annotator 73 | { 74 | public: 75 | enum DeclType { 76 | Declaration, 77 | Definition, 78 | Use, 79 | Use_Read, 80 | Use_Write, 81 | Use_Address, 82 | Use_Call, 83 | Use_MemberAccess, 84 | Use_NestedName, 85 | Override, 86 | Inherit 87 | }; 88 | enum TokenType { 89 | Ref, 90 | Member, 91 | Type, 92 | Decl, 93 | Call, 94 | Namespace, 95 | Typedef, 96 | Enum, 97 | EnumDecl, 98 | Label 99 | }; 100 | 101 | private: 102 | enum class Visibility { 103 | Local, // Local to a Function 104 | Static, // If it is only visible to this file 105 | Global // Globaly visible. 106 | }; 107 | 108 | Visibility getVisibility(const clang::NamedDecl *); 109 | 110 | std::map> cache; 111 | std::map project_cache; 112 | std::map generators; 113 | 114 | std::string htmlNameForFile(clang::FileID id); // keep a cache; 115 | 116 | void addReference(const std::string &ref, clang::SourceRange refLoc, Annotator::TokenType type, 117 | Annotator::DeclType dt, const std::string &typeRef, clang::Decl *decl); 118 | 119 | struct Reference 120 | { 121 | DeclType what; 122 | clang::SourceRange loc; 123 | std::string typeOrContext; 124 | }; 125 | std::map> references; 126 | std::map structure_sizes; 127 | std::map field_offsets; 128 | struct SubRef 129 | { 130 | std::string ref; 131 | std::string type; 132 | enum Type { 133 | None, 134 | Function, 135 | Member, 136 | Static 137 | } what = None; 138 | }; 139 | std::map> sub_refs; 140 | std::unordered_map pathTo_cache; 141 | CommentHandler commentHandler; 142 | 143 | std::unique_ptr mangle; 144 | std::unordered_map> mangle_cache; // canonical Decl* 145 | // -> ref, 146 | // escapred_title 147 | std::pair getReferenceAndTitle(clang::NamedDecl *decl); 148 | // project -> { pretty name, ref } 149 | std::map functionIndex; 150 | 151 | std::unordered_map localeNumbers; 152 | 153 | std::map> interestingDefinitionsInFile; 154 | 155 | std::string args; 156 | clang::SourceManager *sourceManager = nullptr; 157 | const clang::LangOptions *langOption = nullptr; 158 | 159 | void syntaxHighlight(Generator &generator, clang::FileID FID, clang::Sema &); 160 | 161 | public: 162 | explicit Annotator(ProjectManager &pm) 163 | : projectManager(pm) 164 | { 165 | } 166 | ~Annotator(); 167 | 168 | ProjectManager &projectManager; 169 | 170 | void setSourceMgr(clang::SourceManager &sm, const clang::LangOptions &lo) 171 | { 172 | sourceManager = &sm; 173 | langOption = &lo; 174 | } 175 | void setMangleContext(clang::MangleContext *m) 176 | { 177 | mangle.reset(m); 178 | } 179 | clang::SourceManager &getSourceMgr() 180 | { 181 | return *sourceManager; 182 | } 183 | const clang::LangOptions &getLangOpts() const 184 | { 185 | return *langOption; 186 | } 187 | void setArgs(std::string a) 188 | { 189 | args = std::move(a); 190 | } 191 | 192 | bool generate(clang::Sema &, bool WasInDatabase); 193 | 194 | /** 195 | * Returns a string with the URL to go from one file to an other. 196 | * In case the file is in an external project that needs a data-proj tag, the proj 197 | * string is set to the project name. 198 | **/ 199 | std::string pathTo(clang::FileID From, clang::FileID To, std::string *proj = nullptr); 200 | std::string pathTo(clang::FileID From, llvm::StringRef To); 201 | 202 | /** 203 | * Registers that the code in the given \a range refers to the specified declaration. 204 | * This will highlight the rights portion of the code and registers it in the database. 205 | * 206 | * When the range.getEndLocation refers to an invalid location, this means this is a 207 | * virtual range with no associated token (e.g. implicit conversions) which will be handled 208 | * with an empty . 209 | * 210 | * Only use typeRef for declarations (or definition), only use usedContext for uses 211 | */ 212 | void registerReference(clang::NamedDecl *decl, clang::SourceRange range, TokenType type, 213 | DeclType declType = Annotator::Use, std::string typeRef = std::string(), 214 | clang::NamedDecl *usedContext = nullptr); 215 | void registerUse(clang::NamedDecl *decl, clang::SourceRange range, TokenType tt, 216 | clang::NamedDecl *currentContext, DeclType useType = Use) 217 | { 218 | return registerReference(decl, range, tt, useType, {}, currentContext); 219 | } 220 | void registerOverride(clang::NamedDecl *decl, clang::NamedDecl *overrided, 221 | clang::SourceLocation loc); 222 | // same, but for macro 223 | void registerMacro(const std::string &ref, clang::SourceLocation refLoc, DeclType declType); 224 | 225 | // Class names, structs, objective C identifiers, main function 226 | void registerInterestingDefinition(clang::SourceRange range, clang::NamedDecl *decl); 227 | 228 | /** 229 | * Wrap the source range in an HTML tag 230 | */ 231 | void annotateSourceRange(clang::SourceRange range, std::string tag, std::string attributes); 232 | 233 | void reportDiagnostic(clang::SourceRange range, const std::string &msg, 234 | const std::string &clas); 235 | 236 | void addInlayHint(clang::SourceLocation range, std::string inlayHint); 237 | 238 | bool shouldProcess(clang::FileID); 239 | Generator &generator(clang::FileID fid) 240 | { 241 | return generators[fid]; 242 | } 243 | 244 | std::string getTypeRef(clang::QualType type) const; 245 | std::string computeClas(clang::NamedDecl *decl); 246 | std::string getContextStr(clang::NamedDecl *usedContext); 247 | /** 248 | * returns the reference of a class iff this class is visible 249 | * (that is, if a tooltip file should be generated for it) 250 | */ 251 | std::string getVisibleRef(clang::NamedDecl *Decl); 252 | 253 | std::string externalProjectForFile(clang::FileID fid); 254 | 255 | /** 256 | * Returns the param name in function decl for the arg @p arg 257 | * Will be empty if arg->name == paramDecl->name 258 | */ 259 | std::string getParamNameForArg(clang::CallExpr *callExpr, clang::ParmVarDecl *paramDecl, 260 | clang::Expr *arg); 261 | 262 | llvm::DenseMap 263 | getDesignatorInlayHints(clang::InitListExpr *Syn); 264 | }; 265 | -------------------------------------------------------------------------------- /generator/commenthandler.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright (C) 2012-2016 Woboq GmbH 3 | * Olivier Goffart 4 | * https://woboq.com/codebrowser.html 5 | * 6 | * This file is part of the Woboq Code Browser. 7 | * 8 | * Commercial License Usage: 9 | * Licensees holding valid commercial licenses provided by Woboq may use 10 | * this file in accordance with the terms contained in a written agreement 11 | * between the licensee and Woboq. 12 | * For further information see https://woboq.com/codebrowser.html 13 | * 14 | * Alternatively, this work may be used under a Creative Commons 15 | * Attribution-NonCommercial-ShareAlike 3.0 (CC-BY-NC-SA 3.0) License. 16 | * http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US 17 | * This license does not allow you to use the code browser to assist the 18 | * development of your commercial software. If you intent to do so, consider 19 | * purchasing a commercial licence. 20 | ****************************************************************************/ 21 | 22 | #pragma once 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | class Annotator; 29 | namespace clang { 30 | class Preprocessor; 31 | class Sema; 32 | } 33 | 34 | class Generator; 35 | 36 | class CommentHandler 37 | { 38 | struct CommentVisitor; 39 | 40 | public: 41 | struct Doc 42 | { 43 | std::string content; 44 | clang::SourceLocation loc; 45 | }; 46 | 47 | std::multimap docs; 48 | 49 | // fileId -> [ref, global_visibility] 50 | std::multimap> decl_offsets; 51 | 52 | /** 53 | * Handle the comment startig at @a commentstart within @a bufferStart with length @a len. 54 | * Search for corresponding declaration in the given source location interval 55 | * @a commentLoc is the position of the comment 56 | */ 57 | void handleComment(Annotator &A, Generator &generator, clang::Sema &Sema, 58 | const char *bufferStart, int commentStart, int len, 59 | clang::SourceLocation searchLocBegin, clang::SourceLocation searchLocEnd, 60 | clang::SourceLocation commentLoc); 61 | }; -------------------------------------------------------------------------------- /generator/compat.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright (C) 2012-2016 Woboq GmbH 3 | * Olivier Goffart 4 | * https://woboq.com/codebrowser.html 5 | * 6 | * This file is part of the Woboq Code Browser. 7 | * 8 | * Commercial License Usage: 9 | * Licensees holding valid commercial licenses provided by Woboq may use 10 | * this file in accordance with the terms contained in a written agreement 11 | * between the licensee and Woboq. 12 | * For further information see https://woboq.com/codebrowser.html 13 | * 14 | * Alternatively, this work may be used under a Creative Commons 15 | * Attribution-NonCommercial-ShareAlike 3.0 (CC-BY-NC-SA 3.0) License. 16 | * http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US 17 | * This license does not allow you to use the code browser to assist the 18 | * development of your commercial software. If you intent to do so, consider 19 | * purchasing a commercial licence. 20 | ****************************************************************************/ 21 | 22 | #pragma once 23 | 24 | #include 25 | 26 | // clang 3.6 uses unique_ptr in many places that was not using it before 27 | template 28 | struct MaybeUnique 29 | { 30 | T *val; 31 | operator T *() 32 | { 33 | return val; 34 | } 35 | template 36 | operator std::unique_ptr() && 37 | { 38 | return std::unique_ptr(val); 39 | } 40 | }; 41 | template 42 | MaybeUnique maybe_unique(T *val) 43 | { 44 | return { val }; 45 | } 46 | 47 | #ifndef LLVM_FALLTHROUGH 48 | #define LLVM_FALLTHROUGH 49 | #endif 50 | -------------------------------------------------------------------------------- /generator/embedded_includes.h.in: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright (C) 2012-2015 Woboq GmbH 3 | * Olivier Goffart 4 | * https://woboq.com/codebrowser.html 5 | * 6 | * This file is part of the Woboq Code Browser. 7 | * 8 | * Commercial License Usage: 9 | * Licensees holding valid commercial licenses provided by Woboq may use 10 | * this file in accordance with the terms contained in a written agreement 11 | * between the licensee and Woboq. 12 | * For further information see https://woboq.com/codebrowser.html 13 | * 14 | * Alternatively, this work may be used under a Creative Commons 15 | * Attribution-NonCommercial-ShareAlike 3.0 (CC-BY-NC-SA 3.0) License. 16 | * http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US 17 | * This license does not allow you to use the code browser to assist the 18 | * development of your commercial software. If you intent to do so, consider 19 | * purchasing a commercial licence. 20 | ****************************************************************************/ 21 | 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | 30 | struct EmbeddedFile { 31 | const char *filename; 32 | const char *content; 33 | size_t size; 34 | template 35 | constexpr EmbeddedFile(const char *filename, const char (&data)[N]) 36 | : filename(filename) , content(data), size(N-1) {} 37 | constexpr EmbeddedFile () : filename(nullptr) , content(nullptr), size(0) {} 38 | }; 39 | 40 | static constexpr EmbeddedFile EmbeddedFiles[] = { 41 | @EMBEDDED_DATA@ 42 | {} 43 | }; 44 | 45 | 46 | -------------------------------------------------------------------------------- /generator/filesystem.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright (C) 2013 Woboq UG (haftungsbeschraenkt) 3 | * Olivier Goffart 4 | * https://woboq.com/codebrowser.html 5 | * 6 | * This file is part of the Woboq Code Browser. 7 | * 8 | * Commercial License Usage: 9 | * Licensees holding valid commercial licenses provided by Woboq may use 10 | * this file in accordance with the terms contained in a written agreement 11 | * between the licensee and Woboq. 12 | * For further information see https://woboq.com/codebrowser.html 13 | * 14 | * Alternatively, this work may be used under a Creative Commons 15 | * Attribution-NonCommercial-ShareAlike 3.0 (CC-BY-NC-SA 3.0) License. 16 | * http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US 17 | * This license does not allow you to use the code browser to assist the 18 | * development of your commercial software. If you intent to do so, consider 19 | * purchasing a commercial licence. 20 | ****************************************************************************/ 21 | 22 | #include "filesystem.h" 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | #ifndef _WIN32 33 | #include 34 | #include 35 | #else 36 | #include // MAX_PATH 37 | #endif 38 | 39 | void make_forward_slashes(char *str) 40 | { 41 | char *c = strchr(str, '\\'); 42 | while (c) { 43 | *c = '/'; 44 | c = strchr(c + 1, '\\'); 45 | } 46 | } 47 | void make_forward_slashes(std::string &str) 48 | { 49 | std::replace(str.begin(), str.end(), '\\', '/'); 50 | } 51 | 52 | // ATTENTION: Keep in sync with ECMAScript function of the same name in .js files and 53 | // `escapeAttrForFilename` generator.cpp 54 | void replace_invalid_filename_chars(std::string &str) 55 | { 56 | std::replace(str.begin(), str.end(), ':', '.'); 57 | } 58 | 59 | std::error_code canonicalize(const llvm::Twine &path, llvm::SmallVectorImpl &result) 60 | { 61 | std::string p = path.str(); 62 | llvm::sys::fs::real_path(path, result); 63 | 64 | #ifdef _WIN32 65 | // Make sure we use forward slashes to make sure folder detection works as expected everywhere 66 | make_forward_slashes(result.data()); 67 | #endif 68 | 69 | return {}; 70 | } 71 | 72 | std::error_code create_directories(const llvm::Twine &path) 73 | { 74 | using namespace llvm::sys::fs; 75 | auto defaultPerms = perms::all_all & ~perms::group_write & ~perms::others_write; 76 | 77 | return llvm::sys::fs::create_directories(path, true, defaultPerms); 78 | } 79 | 80 | /** 81 | * https://svn.boost.org/trac/boost/ticket/1976#comment:2 82 | * 83 | * "The idea: uncomplete(/foo/new, /foo/bar) => ../new 84 | * The use case for this is any time you get a full path (from an open dialog, perhaps) 85 | * and want to store a relative path so that the group of files can be moved to a different 86 | * directory without breaking the paths. An IDE would be a simple example, so that the 87 | * project file could be safely checked out of subversion." 88 | * 89 | * ALGORITHM: 90 | * iterate path and base 91 | * compare all elements so far of path and base 92 | * whilst they are the same, no write to output 93 | * when they change, or one runs out: 94 | * write to output, ../ times the number of remaining elements in base 95 | * write to output, the remaining elements in path 96 | */ 97 | std::string naive_uncomplete(llvm::StringRef base, llvm::StringRef path) 98 | { 99 | using namespace llvm; 100 | if (sys::path::has_root_path(path)) { 101 | if (sys::path::root_path(path) != sys::path::root_path(base)) { 102 | return std::string(path); 103 | } else { 104 | return naive_uncomplete(sys::path::relative_path(base), sys::path::relative_path(path)); 105 | } 106 | } else { 107 | if (sys::path::has_root_path(base)) { 108 | std::cerr << "naive_uncomplete(" << base.str() << "," << path.str() 109 | << "): cannot uncomplete a path relative path from a rooted base" 110 | << std::endl; 111 | return std::string(path); 112 | } else { 113 | auto path_it = sys::path::begin(path); 114 | auto path_it_end = sys::path::end(path); 115 | auto base_it = sys::path::begin(base); 116 | auto base_it_end = sys::path::end(base); 117 | while (path_it != path_it_end && base_it != base_it_end) { 118 | if (*path_it != *base_it) 119 | break; 120 | ++path_it; 121 | ++base_it; 122 | } 123 | llvm::SmallString<128> result; 124 | for (; base_it != base_it_end; ++base_it) { 125 | sys::path::append(result, ".."); 126 | } 127 | sys::path::append(result, path_it, path_it_end); 128 | return std::string(result.str()); 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /generator/filesystem.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright (C) 2013 Woboq UG (haftungsbeschraenkt) 3 | * Olivier Goffart 4 | * https://woboq.com/codebrowser.html 5 | * 6 | * This file is part of the Woboq Code Browser. 7 | * 8 | * Commercial License Usage: 9 | * Licensees holding valid commercial licenses provided by Woboq may use 10 | * this file in accordance with the terms contained in a written agreement 11 | * between the licensee and Woboq. 12 | * For further information see https://woboq.com/codebrowser.html 13 | * 14 | * Alternatively, this work may be used under a Creative Commons 15 | * Attribution-NonCommercial-ShareAlike 3.0 (CC-BY-NC-SA 3.0) License. 16 | * http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US 17 | * This license does not allow you to use the code browser to assist the 18 | * development of your commercial software. If you intent to do so, consider 19 | * purchasing a commercial licence. 20 | ****************************************************************************/ 21 | 22 | #pragma once 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | namespace llvm { 31 | class Twine; 32 | } 33 | 34 | /* Is declared in llvm::sys::fs, but not implemented */ 35 | std::error_code canonicalize(const llvm::Twine &path, llvm::SmallVectorImpl &result); 36 | 37 | /* The one in llvm::sys::fs do not create the directory with the right peromissions */ 38 | std::error_code create_directories(const llvm::Twine &path); 39 | 40 | std::string naive_uncomplete(llvm::StringRef base, llvm::StringRef path); 41 | 42 | void make_forward_slashes(char *str); 43 | void make_forward_slashes(std::string &str); 44 | void replace_invalid_filename_chars(std::string &str); 45 | -------------------------------------------------------------------------------- /generator/generator.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright (C) 2012-2016 Woboq GmbH 3 | * Olivier Goffart 4 | * https://woboq.com/codebrowser.html 5 | * 6 | * This file is part of the Woboq Code Browser. 7 | * 8 | * Commercial License Usage: 9 | * Licensees holding valid commercial licenses provided by Woboq may use 10 | * this file in accordance with the terms contained in a written agreement 11 | * between the licensee and Woboq. 12 | * For further information see https://woboq.com/codebrowser.html 13 | * 14 | * Alternatively, this work may be used under a Creative Commons 15 | * Attribution-NonCommercial-ShareAlike 3.0 (CC-BY-NC-SA 3.0) License. 16 | * http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US 17 | * This license does not allow you to use the code browser to assist the 18 | * development of your commercial software. If you intent to do so, consider 19 | * purchasing a commercial licence. 20 | ****************************************************************************/ 21 | 22 | #include "generator.h" 23 | #include "filesystem.h" 24 | #include "stringbuilder.h" 25 | 26 | #include "../global.h" 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | template 37 | static void bufferAppend(llvm::SmallVectorImpl &buffer, const char (&val)[N]) 38 | { 39 | buffer.append(val, val + N - 1); 40 | } 41 | 42 | llvm::StringRef Generator::escapeAttr(llvm::StringRef s, llvm::SmallVectorImpl &buffer) 43 | { 44 | buffer.clear(); 45 | unsigned len = s.size(); 46 | for (unsigned i = 0; i < len; ++i) { 47 | char c = s[i]; 48 | switch (c) { 49 | default: 50 | buffer.push_back(c); 51 | break; 52 | case '<': 53 | bufferAppend(buffer, "<"); 54 | break; 55 | case '>': 56 | bufferAppend(buffer, ">"); 57 | break; 58 | case '&': 59 | bufferAppend(buffer, "&"); 60 | break; 61 | case '\"': 62 | bufferAppend(buffer, """); 63 | break; 64 | case '\'': 65 | bufferAppend(buffer, "'"); 66 | break; 67 | } 68 | } 69 | return llvm::StringRef(buffer.begin(), buffer.size()); 70 | } 71 | 72 | void Generator::escapeAttr(llvm::raw_ostream &os, llvm::StringRef s) 73 | { 74 | unsigned len = s.size(); 75 | for (unsigned i = 0; i < len; ++i) { 76 | char c = s[i]; 77 | switch (c) { 78 | default: 79 | os << c; 80 | break; 81 | 82 | case '<': 83 | os << "<"; 84 | break; 85 | case '>': 86 | os << ">"; 87 | break; 88 | case '&': 89 | os << "&"; 90 | break; 91 | case '\"': 92 | os << """; 93 | break; 94 | case '\'': 95 | os << "'"; 96 | break; 97 | } 98 | } 99 | } 100 | 101 | // ATTENTION: Keep in sync with `replace_invalid_filename_chars` functions in filesystem.cpp and in 102 | // .js files 103 | llvm::StringRef Generator::escapeAttrForFilename(llvm::StringRef s, 104 | llvm::SmallVectorImpl &buffer) 105 | { 106 | buffer.clear(); 107 | unsigned len = s.size(); 108 | for (unsigned i = 0; i < len; ++i) { 109 | char c = s[i]; 110 | switch (c) { 111 | default: 112 | buffer.push_back(c); 113 | break; 114 | case ':': 115 | bufferAppend(buffer, "."); 116 | break; 117 | } 118 | } 119 | return llvm::StringRef(buffer.begin(), buffer.size()); 120 | } 121 | 122 | void Generator::Tag::open(llvm::raw_ostream &myfile) const 123 | { 124 | myfile << "<" << name; 125 | if (!attributes.empty()) 126 | myfile << " " << attributes; 127 | 128 | if (len) { 129 | myfile << ">"; 130 | if (!innerHtml.empty()) 131 | myfile << innerHtml; 132 | } else { 133 | // Unfortunately, html5 won't allow or tags, they need to be explicitly 134 | // closed 135 | // myfile << "/>"; 136 | if (!innerHtml.empty()) 137 | myfile << ">" << innerHtml << ""; 138 | else 139 | myfile << ">"; 140 | } 141 | } 142 | 143 | void Generator::Tag::close(llvm::raw_ostream &myfile) const 144 | { 145 | myfile << ""; 146 | } 147 | 148 | void Generator::generate(llvm::StringRef outputPrefix, std::string dataPath, 149 | const std::string &filename, const char *begin, const char *end, 150 | llvm::StringRef footer, llvm::StringRef warningMessage, 151 | const std::set &interestingDefinitions) 152 | { 153 | std::string real_filename = outputPrefix % "/" % filename % ".html"; 154 | // Make sure the parent directory exist: 155 | create_directories(llvm::StringRef(real_filename).rsplit('/').first); 156 | 157 | std::error_code error_code; 158 | llvm::raw_fd_ostream myfile(real_filename, error_code, llvm::sys::fs::OF_None); 159 | if (error_code) { 160 | std::cerr << "Error generating " << real_filename << " "; 161 | std::cerr << error_code.message() << std::endl; 162 | return; 163 | } 164 | 165 | int count = std::count(filename.begin(), filename.end(), '/'); 166 | std::string root_path = ".."; 167 | for (int i = 0; i < count - 1; i++) { 168 | root_path += "/.."; 169 | } 170 | 171 | if (dataPath.size() && dataPath[0] == '.') 172 | dataPath = root_path % "/" % dataPath; 173 | 174 | myfile << "\n" // Use HTML 5 doctype 175 | "\n\n"; 176 | myfile << ""; 177 | myfile << "" << llvm::StringRef(filename).rsplit('/').second.str() << " source code [" 178 | << filename << "] - Woboq Code Browser\n"; 179 | if (interestingDefinitions.size() > 0) { 180 | std::string interestingDefitionsStr = 181 | llvm::join(interestingDefinitions.begin(), interestingDefinitions.end(), ","); 182 | myfile << "\n"; 184 | } 185 | myfile << "\n"; 187 | myfile << "\n"; 189 | myfile << "\n"; 191 | myfile << "\n"; 193 | myfile << "\n"; 207 | myfile << "\n"; 208 | 209 | myfile << "\n\n
"; 232 | 233 | if (!warningMessage.empty()) { 234 | myfile << "

"; 235 | myfile.write(warningMessage.begin(), warningMessage.size()); 236 | myfile << "

\n"; 237 | } 238 | 239 | //** here we put the code 240 | myfile << "
[+] " + 204 | "" + name + "/
" + name + "
\n"; 241 | 242 | 243 | const char *c = begin; 244 | unsigned int line = 1; 245 | const char *bufferStart = c; 246 | 247 | auto tags_it = tags.cbegin(); 248 | const char *next_start = tags_it != tags.cend() ? (begin + tags_it->pos) : end; 249 | const char *next_end = end; 250 | const char *next = next_start; 251 | 252 | 253 | auto flush = [&]() { 254 | if (bufferStart != c) 255 | myfile.write(bufferStart, c - bufferStart); 256 | bufferStart = c; 257 | }; 258 | 259 | myfile << "\n" 304 | "\n" 332 | "
" << 1 << ""; 260 | 261 | std::deque stack; 262 | 263 | 264 | while (true) { 265 | if (c == next) { 266 | flush(); 267 | while (!stack.empty() && c >= next_end) { 268 | const Tag *top = stack.back(); 269 | stack.pop_back(); 270 | top->close(myfile); 271 | next_end = end; 272 | if (!stack.empty()) { 273 | top = stack.back(); 274 | next_end = begin + top->pos + top->len; 275 | } 276 | } 277 | if (c >= end) 278 | break; 279 | assert(c < end); 280 | while (c == next_start && tags_it != tags.cend()) { 281 | assert(c == begin + tags_it->pos); 282 | tags_it->open(myfile); 283 | if (tags_it->len) { 284 | stack.push_back(&(*tags_it)); 285 | next_end = c + tags_it->len; 286 | } 287 | 288 | tags_it++; 289 | next_start = tags_it != tags.cend() ? (begin + tags_it->pos) : end; 290 | }; 291 | 292 | next = std::min(next_end, next_start); 293 | // next = std::min(end, next); 294 | } 295 | 296 | switch (*c) { 297 | case '\n': 298 | flush(); 299 | ++bufferStart; // skip the new line 300 | ++line; 301 | for (auto it = stack.crbegin(); it != stack.crend(); ++it) 302 | (*it)->close(myfile); 303 | myfile << "
" << line << ""; 306 | for (auto it = stack.cbegin(); it != stack.cend(); ++it) 307 | (*it)->open(myfile); 308 | break; 309 | case '&': 310 | flush(); 311 | ++bufferStart; 312 | myfile << "&"; 313 | break; 314 | case '<': 315 | flush(); 316 | ++bufferStart; 317 | myfile << "<"; 318 | break; 319 | case '>': 320 | flush(); 321 | ++bufferStart; 322 | myfile << ">"; 323 | break; 324 | default: 325 | break; 326 | } 327 | ++c; 328 | } 329 | 330 | 331 | myfile << "
" 333 | "
"; 334 | 335 | if (!warningMessage.empty()) { 336 | myfile << "

"; 337 | myfile.write(warningMessage.begin(), warningMessage.size()); 338 | myfile << "

\n"; 339 | } 340 | 341 | myfile << "\n\n"; 349 | } 350 | -------------------------------------------------------------------------------- /generator/generator.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright (C) 2012-2016 Woboq GmbH 3 | * Olivier Goffart 4 | * https://woboq.com/codebrowser.html 5 | * 6 | * This file is part of the Woboq Code Browser. 7 | * 8 | * Commercial License Usage: 9 | * Licensees holding valid commercial licenses provided by Woboq may use 10 | * this file in accordance with the terms contained in a written agreement 11 | * between the licensee and Woboq. 12 | * For further information see https://woboq.com/codebrowser.html 13 | * 14 | * Alternatively, this work may be used under a Creative Commons 15 | * Attribution-NonCommercial-ShareAlike 3.0 (CC-BY-NC-SA 3.0) License. 16 | * http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US 17 | * This license does not allow you to use the code browser to assist the 18 | * development of your commercial software. If you intent to do so, consider 19 | * purchasing a commercial licence. 20 | ****************************************************************************/ 21 | 22 | #pragma once 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace llvm { 32 | class raw_ostream; 33 | } 34 | 35 | 36 | /* This class generate the HTML out of a file with the said tags. 37 | */ 38 | class Generator 39 | { 40 | 41 | struct Tag 42 | { 43 | std::string name; 44 | std::string attributes; 45 | int pos; 46 | int len; 47 | std::string innerHtml; 48 | bool operator<(const Tag &other) const 49 | { 50 | // This is the order of the opening tag. Order first by position, then by length 51 | // (in the reverse order) with the exception of length of 0 which always goes first. 52 | // Ordered first by position, and then by lenth (reverse order) 53 | return (pos != other.pos) ? pos < other.pos 54 | : len == 0 || (other.len != 0 && len > other.len); 55 | } 56 | bool operator==(const Tag &other) const 57 | { 58 | return std::tie(pos, len, name, attributes) 59 | == std::tie(other.pos, other.len, other.name, other.attributes); 60 | } 61 | void open(llvm::raw_ostream &myfile) const; 62 | void close(llvm::raw_ostream &myfile) const; 63 | }; 64 | 65 | std::multiset tags; 66 | 67 | std::map projects; 68 | 69 | public: 70 | void addTag(std::string name, std::string attributes, int pos, int len, 71 | std::string innerHtml = {}) 72 | { 73 | if (len < 0) { 74 | return; 75 | } 76 | Tag t = { std::move(name), std::move(attributes), pos, len, std::move(innerHtml) }; 77 | auto it = tags.find(t); 78 | if (it != tags.end() && *it == t) 79 | return; // Hapens in macro for example 80 | tags.insert(std::move(t)); 81 | } 82 | void addProject(std::string a, std::string b) 83 | { 84 | projects.insert({ std::move(a), std::move(b) }); 85 | } 86 | 87 | void generate(llvm::StringRef outputPrefix, std::string dataPath, const std::string &filename, 88 | const char *begin, const char *end, llvm::StringRef footer, 89 | llvm::StringRef warningMessage, 90 | const std::set &interestingDefitions); 91 | 92 | static llvm::StringRef escapeAttr(llvm::StringRef, llvm::SmallVectorImpl &buffer); 93 | 94 | /** 95 | * This function takes a reference name that was already processed by `escapeAttr` and 96 | * replaces additional chars which are not allowed in filenames on all platforms. 97 | * 98 | * @param s already escaped ref 99 | * @param buffer 100 | * @return 101 | */ 102 | static llvm::StringRef escapeAttrForFilename(llvm::StringRef s, 103 | llvm::SmallVectorImpl &buffer); 104 | static void escapeAttr(llvm::raw_ostream &os, llvm::StringRef s); 105 | 106 | struct EscapeAttr 107 | { 108 | llvm::StringRef value; 109 | }; 110 | }; 111 | 112 | inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, Generator::EscapeAttr s) 113 | { 114 | Generator::escapeAttr(os, s.value); 115 | return os; 116 | } 117 | -------------------------------------------------------------------------------- /generator/inlayhintannotator.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright (C) 2023 Klarälvdalens Datakonsult AB, a KDAB Group company 3 | * 4 | * This file is part of the Code Browser. 5 | * 6 | * Commercial License Usage: 7 | * Licensees holding valid commercial licenses provided by KDAB may use 8 | * this file in accordance with the terms contained in a written agreement 9 | * between the licensee and KDAB. 10 | * For further information see https://codebrowser.dev/ 11 | * 12 | * Alternatively, this work may be used under a Creative Commons 13 | * Attribution-NonCommercial-ShareAlike 3.0 (CC-BY-NC-SA 3.0) License. 14 | * http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US 15 | * This license does not allow you to use the code browser to assist the 16 | * development of your commercial software. If you intent to do so, consider 17 | * purchasing a commercial licence. 18 | *************************************************************************** 19 | * Parts of this code is derived from clangd InlayHints.cpp. License of the file: 20 | * 21 | * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 22 | * See https://llvm.org/LICENSE.txt for license information. 23 | * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 24 | *******************************************************************************/ 25 | #include "inlayhintannotator.h" 26 | #include "annotator.h" 27 | #include "stringbuilder.h" 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | static bool isReservedName(llvm::StringRef id) 37 | { 38 | if (id.size() < 2) 39 | return false; 40 | return id.starts_with("__"); 41 | } 42 | 43 | static llvm::StringRef getSimpleName(const clang::NamedDecl *d) 44 | { 45 | if (clang::IdentifierInfo *Ident = d->getDeclName().getAsIdentifierInfo()) { 46 | return Ident->getName(); 47 | } 48 | return llvm::StringRef(); 49 | } 50 | 51 | // If "E" spells a single unqualified identifier, return that name. 52 | // Otherwise, return an empty string. 53 | static llvm::StringRef getSpelledIdentifier(const clang::Expr *e) 54 | { 55 | e = e->IgnoreUnlessSpelledInSource(); 56 | 57 | if (auto *DRE = llvm::dyn_cast(e)) 58 | if (!DRE->getQualifier()) 59 | return getSimpleName(DRE->getDecl()); 60 | 61 | if (auto *ME = llvm::dyn_cast(e)) 62 | if (!ME->getQualifier() && ME->isImplicitAccess()) 63 | return getSimpleName(ME->getMemberDecl()); 64 | 65 | return {}; 66 | } 67 | 68 | // Helper class to iterate over the designator names of an aggregate type. 69 | // For aggregate classes, yields null for each base, then .field1, .field2, 70 | class AggregateDesignatorNames 71 | { 72 | public: 73 | AggregateDesignatorNames(clang::QualType type) 74 | { 75 | type = type.getCanonicalType(); 76 | if (const clang::RecordDecl *RD = type->getAsRecordDecl()) { 77 | valid = true; 78 | fieldsIt = RD->field_begin(); 79 | fieldsEnd = RD->field_end(); 80 | if (const auto *CRD = llvm::dyn_cast(RD)) { 81 | basesIt = CRD->bases_begin(); 82 | basesEnd = CRD->bases_end(); 83 | valid = CRD->isAggregate(); 84 | } 85 | oneField = valid && basesIt == basesEnd && fieldsIt != fieldsEnd 86 | && std::next(fieldsIt) == fieldsEnd; 87 | } 88 | } 89 | // Returns false if the type was not an aggregate. 90 | operator bool() const 91 | { 92 | return valid; 93 | } 94 | // Advance to the next element in the aggregate. 95 | void next() 96 | { 97 | if (basesIt != basesEnd) 98 | ++basesIt; 99 | else if (fieldsIt != fieldsEnd) 100 | ++fieldsIt; 101 | } 102 | // Print the designator to Out. 103 | // Returns false if we could not produce a designator for this element. 104 | bool append(std::string &out, bool forSubobject) 105 | { 106 | if (basesIt != basesEnd) 107 | return false; // Bases can't be designated. Should we make one 108 | // up? 109 | if (fieldsIt != fieldsEnd) { 110 | llvm::StringRef fieldName; 111 | if (const clang::IdentifierInfo *ii = fieldsIt->getIdentifier()) 112 | fieldName = ii->getName(); 113 | 114 | // For certain objects, their subobjects may be named directly. 115 | if (forSubobject 116 | && (fieldsIt->isAnonymousStructOrUnion() || 117 | // std::array x = {1,2,3}. 118 | // Designators not strictly valid! 119 | (oneField && isReservedName(fieldName)))) 120 | return true; 121 | 122 | if (!fieldName.empty() && !isReservedName(fieldName)) { 123 | out.push_back('.'); 124 | out.append(fieldName.begin(), fieldName.end()); 125 | return true; 126 | } 127 | return false; 128 | } 129 | return false; 130 | } 131 | 132 | private: 133 | bool valid = false; 134 | bool oneField = false; // e.g. std::array { T __elements[N]; } 135 | clang::CXXRecordDecl::base_class_const_iterator basesIt; 136 | clang::CXXRecordDecl::base_class_const_iterator basesEnd; 137 | clang::RecordDecl::field_iterator fieldsIt; 138 | clang::RecordDecl::field_iterator fieldsEnd; 139 | }; 140 | 141 | static void collectDesignators(const clang::InitListExpr *sem, 142 | llvm::DenseMap &out, 143 | const llvm::DenseSet &nestedBraces, 144 | std::string &prefix) 145 | { 146 | if (!sem || sem->isTransparent() || !sem->isSemanticForm()) 147 | return; 148 | // Nothing to do for arrays 149 | if (sem->getType().isNull() || sem->getType().getCanonicalType()->isArrayType()) 150 | return; 151 | 152 | // The elements of the semantic form all correspond to direct subobjects 153 | // of the aggregate type. `Fields` iterates over these subobject names. 154 | AggregateDesignatorNames fields(sem->getType()); 155 | if (!fields) 156 | return; 157 | 158 | for (const clang::Expr *init : sem->inits()) { 159 | struct RAII 160 | { 161 | AggregateDesignatorNames &fields; 162 | std::string &prefix; 163 | const int size = prefix.size(); 164 | ~RAII() 165 | { 166 | fields.next(); // Always advance to the next subobject name. 167 | prefix.resize(size); // Erase any designator we appended. 168 | } 169 | }; 170 | auto next = RAII { fields, prefix }; 171 | // Skip for a broken initializer or if it is a "hole" in a subobject 172 | // that was not explicitly initialized. 173 | if (!init || llvm::isa(init)) 174 | continue; 175 | 176 | const auto *braceElidedSubobject = llvm::dyn_cast(init); 177 | if (braceElidedSubobject && nestedBraces.contains(braceElidedSubobject->getLBraceLoc())) 178 | braceElidedSubobject = nullptr; // there were braces! 179 | 180 | if (!fields.append(prefix, braceElidedSubobject != nullptr)) 181 | continue; // no designator available for this subobject 182 | if (braceElidedSubobject) { 183 | // If the braces were elided, this aggregate subobject is 184 | // initialized inline in the same syntactic list. Descend into 185 | // the semantic list describing the subobject. (NestedBraces are 186 | // still correct, they're from the same syntactic list). 187 | collectDesignators(braceElidedSubobject, out, nestedBraces, prefix); 188 | continue; 189 | } 190 | out.try_emplace(init->getBeginLoc(), prefix); 191 | } 192 | } 193 | 194 | InlayHintsAnnotatorHelper::InlayHintsAnnotatorHelper(Annotator *annotator) 195 | : SM(annotator->getSourceMgr()) 196 | , mainFileID(SM.getMainFileID()) 197 | { 198 | } 199 | 200 | llvm::DenseMap 201 | InlayHintsAnnotatorHelper::getDesignatorInlayHints(clang::InitListExpr *Syn) 202 | { 203 | // collectDesignators needs to know which InitListExprs in the semantic 204 | // tree were actually written, but InitListExpr::isExplicit() lies. 205 | // Instead, record where braces of sub-init-lists occur in the syntactic 206 | // form. 207 | llvm::DenseSet nestedBraces; 208 | for (const clang::Expr *init : Syn->inits()) 209 | if (auto *nested = llvm::dyn_cast(init)) 210 | nestedBraces.insert(nested->getLBraceLoc()); 211 | 212 | // Traverse the semantic form to find the designators. 213 | // We use their SourceLocation to correlate with the syntactic form 214 | // later. 215 | llvm::DenseMap designators; 216 | std::string emptyPrefix; 217 | collectDesignators(Syn->isSemanticForm() ? Syn : Syn->getSemanticForm(), designators, 218 | nestedBraces, emptyPrefix); 219 | 220 | llvm::StringRef Buf = SM.getBufferData(mainFileID); 221 | llvm::DenseMap designatorSpans; 222 | 223 | for (const clang::Expr *init : Syn->inits()) { 224 | if (llvm::isa(init)) 225 | continue; 226 | auto it = designators.find(init->getBeginLoc()); 227 | if (it != designators.end() && !isPrecededByParamNameComment(init, it->second, Buf)) { 228 | designatorSpans.try_emplace(init->getBeginLoc(), it->second % ": "); 229 | } 230 | } 231 | return designatorSpans; 232 | } 233 | 234 | bool InlayHintsAnnotatorHelper::isPrecededByParamNameComment(const clang::Expr *E, 235 | llvm::StringRef paramName, 236 | llvm::StringRef mainFileBuf) 237 | { 238 | auto exprStartLoc = SM.getTopMacroCallerLoc(E->getBeginLoc()); 239 | auto decomposed = SM.getDecomposedLoc(exprStartLoc); 240 | if (decomposed.first != mainFileID) 241 | return false; 242 | 243 | llvm::StringRef sourcePrefix = mainFileBuf.substr(0, decomposed.second); 244 | // Allow whitespace between comment and expression. 245 | sourcePrefix = sourcePrefix.rtrim(); 246 | // Check for comment ending. 247 | if (!sourcePrefix.consume_back("*/")) 248 | return false; 249 | // Ignore some punctuation and whitespace around comment. 250 | // In particular this allows designators to match nicely. 251 | llvm::StringLiteral ignoreChars = " =."; 252 | sourcePrefix = sourcePrefix.rtrim(ignoreChars); 253 | paramName = paramName.trim(ignoreChars); 254 | // Other than that, the comment must contain exactly ParamName. 255 | if (!sourcePrefix.consume_back(paramName)) 256 | return false; 257 | sourcePrefix = sourcePrefix.rtrim(ignoreChars); 258 | return sourcePrefix.ends_with("/*"); 259 | } 260 | 261 | std::string InlayHintsAnnotatorHelper::getParamNameInlayHint(clang::CallExpr *e, 262 | clang::ParmVarDecl *paramDecl, 263 | clang::Expr *arg) 264 | { 265 | if (e->isCallToStdMove() || llvm::isa(e) 266 | || llvm::isa(e)) 267 | return {}; 268 | 269 | auto f = e->getDirectCallee(); 270 | if (!f) 271 | return {}; 272 | 273 | // simple setter? => ignore 274 | if (f->getNumParams() == 1 && getSimpleName(f).starts_with_insensitive("set")) 275 | return {}; 276 | 277 | llvm::StringRef paramName = getSimpleName(paramDecl); 278 | if (paramName.empty() || paramName == getSpelledIdentifier(arg)) 279 | return {}; 280 | 281 | paramName = paramName.ltrim('_'); 282 | if (isPrecededByParamNameComment(arg, paramName, SM.getBufferData(mainFileID))) 283 | return {}; 284 | 285 | auto t = paramDecl->getType(); 286 | bool isLValueRef = t->isLValueReferenceType() && !t.getNonReferenceType().isConstQualified(); 287 | llvm::StringRef refStr = isLValueRef ? "&" : llvm::StringRef(); 288 | return paramName % refStr % ": "; 289 | } 290 | -------------------------------------------------------------------------------- /generator/inlayhintannotator.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright (C) 2023 Klarälvdalens Datakonsult AB, a KDAB Group company 3 | * 4 | * This file is part of the Code Browser. 5 | * 6 | * Commercial License Usage: 7 | * Licensees holding valid commercial licenses provided by KDAB may use 8 | * this file in accordance with the terms contained in a written agreement 9 | * between the licensee and KDAB. 10 | * For further information see https://codebrowser.dev/ 11 | * 12 | * Alternatively, this work may be used under a Creative Commons 13 | * Attribution-NonCommercial-ShareAlike 3.0 (CC-BY-NC-SA 3.0) License. 14 | * http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US 15 | * This license does not allow you to use the code browser to assist the 16 | * development of your commercial software. If you intent to do so, consider 17 | * purchasing a commercial licence. 18 | ****************************************************************************/ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | 25 | class Annotator; 26 | 27 | class InlayHintsAnnotatorHelper 28 | { 29 | public: 30 | InlayHintsAnnotatorHelper(Annotator *annotator); 31 | 32 | llvm::DenseMap 33 | getDesignatorInlayHints(clang::InitListExpr *Syn); 34 | 35 | std::string getParamNameInlayHint(clang::CallExpr *callExpr, clang::ParmVarDecl *paramDecl, 36 | clang::Expr *arg); 37 | 38 | private: 39 | // Checks if "E" is spelled in the main file and preceded by a C-style comment 40 | // whose contents match ParamName (allowing for whitespace and an optional "=" 41 | // at the end. 42 | bool isPrecededByParamNameComment(const clang::Expr *E, llvm::StringRef ParamName, 43 | llvm::StringRef mainFileBuf); 44 | 45 | clang::SourceManager &SM; 46 | clang::FileID mainFileID; 47 | }; 48 | -------------------------------------------------------------------------------- /generator/preprocessorcallback.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright (C) 2012-2016 Woboq GmbH 3 | * Olivier Goffart 4 | * https://woboq.com/codebrowser.html 5 | * 6 | * This file is part of the Woboq Code Browser. 7 | * 8 | * Commercial License Usage: 9 | * Licensees holding valid commercial licenses provided by Woboq may use 10 | * this file in accordance with the terms contained in a written agreement 11 | * between the licensee and Woboq. 12 | * For further information see https://woboq.com/codebrowser.html 13 | * 14 | * Alternatively, this work may be used under a Creative Commons 15 | * Attribution-NonCommercial-ShareAlike 3.0 (CC-BY-NC-SA 3.0) License. 16 | * http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US 17 | * This license does not allow you to use the code browser to assist the 18 | * development of your commercial software. If you intent to do so, consider 19 | * purchasing a commercial licence. 20 | ****************************************************************************/ 21 | 22 | #include "preprocessorcallback.h" 23 | #include "annotator.h" 24 | #include "stringbuilder.h" 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | 33 | void PreprocessorCallback::MacroExpands(const clang::Token &MacroNameTok, MyMacroDefinition MD, 34 | clang::SourceRange Range, const clang::MacroArgs *) 35 | { 36 | if (disabled) 37 | return; 38 | 39 | auto *MI = MD.getMacroInfo(); 40 | clang::SourceLocation loc = MacroNameTok.getLocation(); 41 | if (!loc.isValid() || !loc.isFileID()) 42 | return; 43 | clang::SourceManager &sm = annotator.getSourceMgr(); 44 | clang::FileID FID = sm.getFileID(loc); 45 | if (!annotator.shouldProcess(FID)) 46 | return; 47 | 48 | const char *begin = sm.getCharacterData(Range.getBegin()); 49 | int len = sm.getCharacterData(Range.getEnd()) - begin; 50 | len += clang::Lexer::MeasureTokenLength(Range.getEnd(), sm, PP.getLangOpts()); 51 | 52 | std::string copy(begin, len); 53 | begin = copy.c_str(); 54 | clang::Lexer lex(loc, PP.getLangOpts(), begin, begin, begin + len); 55 | std::vector tokens; 56 | std::string expansion; 57 | 58 | // Lousely based on code from clang::html::HighlightMacros 59 | 60 | // Lex all the tokens in raw mode, to avoid entering #includes or expanding 61 | // macros. 62 | clang::Token tok; 63 | do { 64 | lex.LexFromRawLexer(tok); 65 | 66 | // If this is a # at the start of a line, discard it from the token stream. 67 | // We don't want the re-preprocess step to see #defines, #includes or other 68 | // preprocessor directives. 69 | if (tok.is(clang::tok::hash) && tok.isAtStartOfLine()) 70 | continue; 71 | 72 | // If this is a ## token, change its kind to unknown so that repreprocessing 73 | // it will not produce an error. 74 | if (tok.is(clang::tok::hashhash)) 75 | tok.setKind(clang::tok::unknown); 76 | 77 | // If this raw token is an identifier, the raw lexer won't have looked up 78 | // the corresponding identifier info for it. Do this now so that it will be 79 | // macro expanded when we re-preprocess it. 80 | if (tok.is(clang::tok::raw_identifier)) 81 | PP.LookUpIdentifierInfo(tok); 82 | 83 | tokens.push_back(tok); 84 | 85 | } while (!tok.is(clang::tok::eof)); 86 | 87 | // Temporarily change the diagnostics object so that we ignore any generated 88 | // diagnostics from this pass. 89 | clang::DiagnosticsEngine TmpDiags(PP.getDiagnostics().getDiagnosticIDs(), 90 | &PP.getDiagnostics().getDiagnosticOptions(), 91 | new clang::IgnoringDiagConsumer); 92 | 93 | disabled = true; 94 | clang::DiagnosticsEngine *OldDiags = &PP.getDiagnostics(); 95 | PP.setDiagnostics(TmpDiags); 96 | 97 | // We don't want pragmas either. Although we filtered out #pragma, removing 98 | // _Pragma and __pragma is much harder. 99 | bool pragmasPreviouslyEnabled = PP.getPragmasEnabled(); 100 | PP.setPragmasEnabled(false); 101 | seenPragma = false; 102 | 103 | PP.EnterTokenStream(tokens, /*DisableMacroExpansion=*/false, /*IsReinject=*/false); 104 | PP.Lex(tok); 105 | while (tok.isNot(clang::tok::eof)) { 106 | if (seenPragma) { 107 | // skip pragma 108 | while (tok.isNot(clang::tok::eof) && tok.isNot(clang::tok::eod)) 109 | PP.Lex(tok); 110 | seenPragma = false; 111 | PP.Lex(tok); 112 | continue; 113 | } 114 | 115 | // If the tokens were already space separated, or if they must be to avoid 116 | // them being implicitly pasted, add a space between them. 117 | if (tok.hasLeadingSpace()) 118 | expansion += ' '; 119 | // ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok)) //FIXME 120 | // Escape any special characters in the token text. 121 | expansion += PP.getSpelling(tok); 122 | 123 | if (expansion.size() >= 30 * 1000) { 124 | // Don't let the macro expansion grow too large. 125 | expansion += "..."; 126 | while (tok.isNot(clang::tok::eof)) 127 | PP.LexUnexpandedToken(tok); 128 | break; 129 | } 130 | 131 | PP.Lex(tok); 132 | } 133 | 134 | PP.setDiagnostics(*OldDiags); 135 | PP.setPragmasEnabled(pragmasPreviouslyEnabled); 136 | disabled = false; 137 | 138 | std::string ref = llvm::Twine("_M/", MacroNameTok.getIdentifierInfo()->getName()).str(); 139 | 140 | clang::SourceLocation defLoc = MI->getDefinitionLoc(); 141 | clang::FileID defFID = sm.getFileID(defLoc); 142 | llvm::SmallString<128> expansionBuffer; 143 | std::string link; 144 | std::string dataProj; 145 | if (defFID != FID) { 146 | link = annotator.pathTo(FID, defFID, &dataProj); 147 | if (link.empty()) { 148 | std::string tag = "class=\"macro\" title=\"" 149 | % Generator::escapeAttr(expansion, expansionBuffer) % "\" data-ref=\"" % ref % "\""; 150 | annotator.generator(FID).addTag("span", tag, sm.getFileOffset(loc), 151 | MacroNameTok.getLength()); 152 | return; 153 | } 154 | 155 | if (!dataProj.empty()) { 156 | dataProj = " data-proj=\"" % dataProj % "\""; 157 | } 158 | } 159 | 160 | if (sm.getMainFileID() != defFID) { 161 | annotator.registerMacro(ref, MacroNameTok.getLocation(), Annotator::Use_Call); 162 | } 163 | 164 | std::string tag = "class=\"macro\" href=\"" % link % "#" 165 | % llvm::Twine(sm.getExpansionLineNumber(defLoc)).str() % "\" title=\"" 166 | % Generator::escapeAttr(expansion, expansionBuffer) % "\" data-ref=\"" % ref % "\"" 167 | % dataProj; 168 | annotator.generator(FID).addTag("a", tag, sm.getFileOffset(loc), MacroNameTok.getLength()); 169 | } 170 | 171 | void PreprocessorCallback::MacroDefined(const clang::Token &MacroNameTok, 172 | const clang::MacroDirective *MD) 173 | { 174 | clang::SourceLocation loc = MacroNameTok.getLocation(); 175 | if (!loc.isValid() || !loc.isFileID()) 176 | return; 177 | 178 | clang::SourceManager &sm = annotator.getSourceMgr(); 179 | clang::FileID FID = sm.getFileID(loc); 180 | if (!annotator.shouldProcess(FID)) 181 | return; 182 | 183 | std::string ref = llvm::Twine("_M/", MacroNameTok.getIdentifierInfo()->getName()).str(); 184 | 185 | if (sm.getMainFileID() != FID) { 186 | annotator.registerMacro(ref, MacroNameTok.getLocation(), Annotator::Declaration); 187 | } 188 | 189 | annotator.generator(FID).addTag("dfn", 190 | "class=\"macro\" id=\"" % ref % "\" data-ref=\"" % ref % "\"", 191 | sm.getFileOffset(loc), MacroNameTok.getLength()); 192 | } 193 | 194 | void PreprocessorCallback::MacroUndefined(const clang::Token &MacroNameTok, 195 | PreprocessorCallback::MyMacroDefinition MD, 196 | const clang::MacroDirective *) 197 | { 198 | clang::SourceLocation loc = MacroNameTok.getLocation(); 199 | if (!loc.isValid() || !loc.isFileID()) 200 | return; 201 | 202 | clang::SourceManager &sm = annotator.getSourceMgr(); 203 | clang::FileID FID = sm.getFileID(loc); 204 | if (!annotator.shouldProcess(FID)) 205 | return; 206 | 207 | std::string ref = llvm::Twine("_M/", MacroNameTok.getIdentifierInfo()->getName()).str(); 208 | std::string link; 209 | std::string dataProj; 210 | clang::SourceLocation defLoc; 211 | clang::FileID defFID; 212 | 213 | if (MD) { 214 | auto *MI = MD.getMacroInfo(); 215 | if (MI) { 216 | defLoc = MI->getDefinitionLoc(); 217 | defFID = sm.getFileID(defLoc); 218 | } 219 | } 220 | 221 | if (defFID.isInvalid() || defFID != FID) { 222 | if (!defFID.isInvalid()) { 223 | link = annotator.pathTo(FID, defFID, &dataProj); 224 | } 225 | if (link.empty()) { 226 | std::string tag = "class=\"macro\" data-ref=\"" % ref % "\""; 227 | annotator.generator(FID).addTag("span", tag, sm.getFileOffset(loc), 228 | MacroNameTok.getLength()); 229 | return; 230 | } 231 | 232 | if (!dataProj.empty()) { 233 | dataProj = " data-proj=\"" % dataProj % "\""; 234 | } 235 | } 236 | 237 | if (sm.getMainFileID() != defFID) { 238 | annotator.registerMacro(ref, MacroNameTok.getLocation(), Annotator::Use_Write); 239 | } 240 | 241 | std::string tag = "class=\"macro\" href=\"" % link % "#" 242 | % llvm::Twine(sm.getExpansionLineNumber(defLoc)).str() % "\" data-ref=\"" % ref % "\"" 243 | % dataProj; 244 | annotator.generator(FID).addTag("a", tag, sm.getFileOffset(loc), MacroNameTok.getLength()); 245 | } 246 | 247 | void PreprocessorCallback::InclusionDirective( 248 | clang::SourceLocation HashLoc, const clang::Token &IncludeTok, llvm::StringRef FileName, 249 | bool IsAngled, clang::CharSourceRange FilenameRange, clang::OptionalFileEntryRef File, 250 | llvm::StringRef SearchPath, llvm::StringRef RelativePath, const clang::Module *Imported, 251 | #if CLANG_VERSION_MAJOR >= 19 252 | bool ModuleImported, 253 | #endif 254 | clang::SrcMgr::CharacteristicKind) 255 | { 256 | if (!HashLoc.isValid() || !HashLoc.isFileID() || !File) 257 | return; 258 | clang::SourceManager &sm = annotator.getSourceMgr(); 259 | clang::FileID FID = sm.getFileID(HashLoc); 260 | if (!annotator.shouldProcess(FID)) 261 | return; 262 | 263 | std::string link = annotator.pathTo(FID, File->getName()); 264 | if (link.empty()) 265 | return; 266 | 267 | auto B = sm.getFileOffset(FilenameRange.getBegin()); 268 | auto E = sm.getFileOffset(FilenameRange.getEnd()); 269 | 270 | annotator.generator(FID).addTag("a", "href=\"" % link % "\"", B, E - B); 271 | } 272 | 273 | void PreprocessorCallback::Defined(const clang::Token &MacroNameTok, MyMacroDefinition MD, 274 | clang::SourceRange Range) 275 | { 276 | clang::SourceLocation loc = MacroNameTok.getLocation(); 277 | if (!loc.isValid() || !loc.isFileID()) 278 | return; 279 | 280 | clang::SourceManager &sm = annotator.getSourceMgr(); 281 | 282 | clang::FileID FID = sm.getFileID(loc); 283 | if (!annotator.shouldProcess(FID)) 284 | return; 285 | 286 | std::string ref = llvm::Twine("_M/", MacroNameTok.getIdentifierInfo()->getName()).str(); 287 | std::string link; 288 | std::string dataProj; 289 | clang::SourceLocation defLoc; 290 | clang::FileID defFID; 291 | 292 | if (MD) { 293 | auto *MI = MD.getMacroInfo(); 294 | if (MI) { 295 | defLoc = MI->getDefinitionLoc(); 296 | defFID = sm.getFileID(defLoc); 297 | } 298 | } 299 | 300 | if (defFID.isInvalid() || defFID != FID) { 301 | if (!defFID.isInvalid()) { 302 | link = annotator.pathTo(FID, defFID, &dataProj); 303 | } 304 | if (link.empty()) { 305 | std::string tag = "class=\"macro\" data-ref=\"" % ref % "\""; 306 | annotator.generator(FID).addTag("span", tag, sm.getFileOffset(loc), 307 | MacroNameTok.getLength()); 308 | return; 309 | } 310 | 311 | if (!dataProj.empty()) { 312 | dataProj = " data-proj=\"" % dataProj % "\""; 313 | } 314 | } 315 | 316 | if (sm.getMainFileID() != defFID) { 317 | annotator.registerMacro(ref, MacroNameTok.getLocation(), Annotator::Use_Address); 318 | } 319 | 320 | std::string tag = "class=\"macro\" href=\"" % link % "#" 321 | % llvm::Twine(sm.getExpansionLineNumber(defLoc)).str() % "\" data-ref=\"" % ref % "\"" 322 | % dataProj; 323 | annotator.generator(FID).addTag("a", tag, sm.getFileOffset(loc), MacroNameTok.getLength()); 324 | } 325 | 326 | void PreprocessorCallback::HandlePPCond(clang::SourceLocation Loc, clang::SourceLocation IfLoc) 327 | { 328 | if (!Loc.isValid() || !Loc.isFileID()) 329 | return; 330 | 331 | clang::SourceManager &SM = annotator.getSourceMgr(); 332 | clang::FileID FID = SM.getFileID(Loc); 333 | if (!annotator.shouldProcess(FID)) 334 | return; 335 | 336 | while (ElifMapping.count(IfLoc)) { 337 | IfLoc = Loc; 338 | } 339 | 340 | if (SM.getFileID(IfLoc) != FID) { 341 | return; 342 | } 343 | 344 | annotator.generator(FID).addTag( 345 | "span", ("data-ppcond=\"" + clang::Twine(SM.getExpansionLineNumber(IfLoc)) + "\"").str(), 346 | SM.getFileOffset(Loc), clang::Lexer::MeasureTokenLength(Loc, SM, PP.getLangOpts())); 347 | } 348 | -------------------------------------------------------------------------------- /generator/preprocessorcallback.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright (C) 2012-2016 Woboq GmbH 3 | * Olivier Goffart 4 | * https://woboq.com/codebrowser.html 5 | * 6 | * This file is part of the Woboq Code Browser. 7 | * 8 | * Commercial License Usage: 9 | * Licensees holding valid commercial licenses provided by Woboq may use 10 | * this file in accordance with the terms contained in a written agreement 11 | * between the licensee and Woboq. 12 | * For further information see https://woboq.com/codebrowser.html 13 | * 14 | * Alternatively, this work may be used under a Creative Commons 15 | * Attribution-NonCommercial-ShareAlike 3.0 (CC-BY-NC-SA 3.0) License. 16 | * http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US 17 | * This license does not allow you to use the code browser to assist the 18 | * development of your commercial software. If you intent to do so, consider 19 | * purchasing a commercial licence. 20 | ****************************************************************************/ 21 | 22 | 23 | #pragma once 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | namespace clang { 30 | class Preprocessor; 31 | } 32 | 33 | class Annotator; 34 | 35 | class PreprocessorCallback : public clang::PPCallbacks 36 | { 37 | Annotator &annotator; 38 | clang::Preprocessor &PP; 39 | bool disabled = false; // To prevent recurstion 40 | bool seenPragma = false; // To detect _Pragma in expansion 41 | bool recoverIncludePath; // If we should try to find the include paths harder 42 | 43 | public: 44 | PreprocessorCallback(Annotator &fm, clang::Preprocessor &PP, bool recoverIncludePath) 45 | : annotator(fm) 46 | , PP(PP) 47 | , recoverIncludePath(recoverIncludePath) 48 | { 49 | } 50 | 51 | using MyMacroDefinition = const clang::MacroDefinition &; 52 | void MacroExpands(const clang::Token &MacroNameTok, MyMacroDefinition MD, 53 | clang::SourceRange Range, const clang::MacroArgs *Args) override; 54 | 55 | void MacroDefined(const clang::Token &MacroNameTok, const clang::MacroDirective *MD) override; 56 | 57 | void MacroUndefined(const clang::Token &MacroNameTok, MyMacroDefinition MD, 58 | const clang::MacroDirective *) override; 59 | 60 | void InclusionDirective(clang::SourceLocation HashLoc, const clang::Token &IncludeTok, 61 | llvm::StringRef FileName, bool IsAngled, 62 | clang::CharSourceRange FilenameRange, clang::OptionalFileEntryRef File, 63 | llvm::StringRef SearchPath, llvm::StringRef RelativePath, 64 | const clang::Module *SuggestedModule, 65 | #if CLANG_VERSION_MAJOR >= 19 66 | bool ModuleImported, 67 | #endif 68 | clang::SrcMgr::CharacteristicKind FileType) override; 69 | 70 | void PragmaDirective(clang::SourceLocation Loc, clang::PragmaIntroducerKind Introducer) override 71 | { 72 | seenPragma = true; 73 | } 74 | 75 | virtual void If(clang::SourceLocation Loc, clang::SourceRange ConditionRange, 76 | ConditionValueKind ConditionValue) override 77 | { 78 | HandlePPCond(Loc, Loc); 79 | } 80 | virtual void Ifndef(clang::SourceLocation Loc, const clang::Token &MacroNameTok, 81 | MyMacroDefinition MD) override 82 | { 83 | HandlePPCond(Loc, Loc); 84 | Defined(MacroNameTok, MD, Loc); 85 | } 86 | virtual void Ifdef(clang::SourceLocation Loc, const clang::Token &MacroNameTok, 87 | MyMacroDefinition MD) override 88 | { 89 | HandlePPCond(Loc, Loc); 90 | Defined(MacroNameTok, MD, Loc); 91 | } 92 | virtual void Elif(clang::SourceLocation Loc, clang::SourceRange ConditionRange, 93 | ConditionValueKind ConditionValue, clang::SourceLocation IfLoc) override 94 | { 95 | ElifMapping[Loc] = IfLoc; 96 | HandlePPCond(Loc, IfLoc); 97 | } 98 | virtual void Else(clang::SourceLocation Loc, clang::SourceLocation IfLoc) override 99 | { 100 | HandlePPCond(Loc, IfLoc); 101 | } 102 | virtual void Endif(clang::SourceLocation Loc, clang::SourceLocation IfLoc) override 103 | { 104 | HandlePPCond(Loc, IfLoc); 105 | } 106 | 107 | virtual void Defined(const clang::Token &MacroNameTok, MyMacroDefinition MD, 108 | clang::SourceRange Range) override; 109 | 110 | private: 111 | std::map ElifMapping; // Map an elif location to 112 | // the real if; 113 | void HandlePPCond(clang::SourceLocation Loc, clang::SourceLocation IfLoc); 114 | }; 115 | -------------------------------------------------------------------------------- /generator/projectmanager.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright (C) 2012-2016 Woboq GmbH 3 | * Olivier Goffart 4 | * https://woboq.com/codebrowser.html 5 | * 6 | * This file is part of the Woboq Code Browser. 7 | * 8 | * Commercial License Usage: 9 | * Licensees holding valid commercial licenses provided by Woboq may use 10 | * this file in accordance with the terms contained in a written agreement 11 | * between the licensee and Woboq. 12 | * For further information see https://woboq.com/codebrowser.html 13 | * 14 | * Alternatively, this work may be used under a Creative Commons 15 | * Attribution-NonCommercial-ShareAlike 3.0 (CC-BY-NC-SA 3.0) License. 16 | * http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US 17 | * This license does not allow you to use the code browser to assist the 18 | * development of your commercial software. If you intent to do so, consider 19 | * purchasing a commercial licence. 20 | ****************************************************************************/ 21 | 22 | #include "projectmanager.h" 23 | #include "filesystem.h" 24 | #include "stringbuilder.h" 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | ProjectManager::ProjectManager(std::string outputPrefix, std::string _dataPath) 32 | : outputPrefix(std::move(outputPrefix)) 33 | , dataPath(std::move(_dataPath)) 34 | { 35 | if (dataPath.empty()) 36 | dataPath = "../data"; 37 | 38 | for (auto &&info : systemProjects()) { 39 | addProject(info); 40 | } 41 | } 42 | 43 | bool ProjectManager::addProject(ProjectInfo info) 44 | { 45 | if (info.source_path.empty()) 46 | return false; 47 | llvm::SmallString<256> filename; 48 | canonicalize(info.source_path, filename); 49 | if (filename.empty()) 50 | return false; 51 | if (filename[filename.size() - 1] != '/') 52 | filename += '/'; 53 | info.source_path = filename.c_str(); 54 | 55 | projects.push_back(std::move(info)); 56 | return true; 57 | } 58 | 59 | ProjectInfo *ProjectManager::projectForFile(llvm::StringRef filename) 60 | { 61 | unsigned int match_length = 0; 62 | ProjectInfo *result = nullptr; 63 | 64 | for (auto &it : projects) { 65 | const std::string &source_path = it.source_path; 66 | if (source_path.size() < match_length) { 67 | continue; 68 | } 69 | if (filename.starts_with(source_path)) { 70 | result = ⁢ 71 | match_length = source_path.size(); 72 | } 73 | } 74 | return result; 75 | } 76 | 77 | bool ProjectManager::shouldProcess(llvm::StringRef filename, ProjectInfo *project) const 78 | { 79 | if (!project) 80 | return false; 81 | if (project->type == ProjectInfo::External) 82 | return false; 83 | 84 | std::string fn = outputPrefix % "/" % project->name % "/" 85 | % filename.substr(project->source_path.size()) % ".html"; 86 | return !llvm::sys::fs::exists(fn); 87 | // || boost::filesystem::last_write_time(p) < entry->getModificationTime(); 88 | } 89 | 90 | std::string ProjectManager::includeRecovery(llvm::StringRef includeName, llvm::StringRef from) 91 | { 92 | if (includeRecoveryCache.empty()) { 93 | for (const auto &proj : projects) { 94 | // skip sub project 95 | llvm::StringRef sourcePath(proj.source_path); 96 | auto parentPath = sourcePath.substr(0, sourcePath.rfind('/')); 97 | if (projectForFile(parentPath)) 98 | continue; 99 | 100 | std::error_code EC; 101 | for (llvm::sys::fs::recursive_directory_iterator it(sourcePath, EC), DirEnd; 102 | it != DirEnd && !EC; it.increment(EC)) { 103 | auto fileName = llvm::sys::path::filename(it->path()); 104 | if (fileName.starts_with(".")) { 105 | it.no_push(); 106 | continue; 107 | } 108 | includeRecoveryCache.insert({ std::string(fileName), it->path() }); 109 | } 110 | } 111 | } 112 | llvm::StringRef includeFileName = llvm::sys::path::filename(includeName); 113 | std::string resolved; 114 | int weight = -1000; 115 | auto range = includeRecoveryCache.equal_range(std::string(includeFileName)); 116 | for (auto it = range.first; it != range.second; ++it) { 117 | llvm::StringRef candidate(it->second); 118 | unsigned int suf_len = 0; 119 | while (suf_len < std::min(candidate.size(), includeName.size())) { 120 | if (candidate[candidate.size() - suf_len - 1] 121 | != includeName[includeName.size() - suf_len - 1]) 122 | break; 123 | suf_len++; 124 | } 125 | // Each paths part that are similar from the expected name are weighted 1000 points f 126 | int w = includeName.substr(includeName.size() - suf_len).count('/') * 1000; 127 | if (w + 1000 < weight) 128 | continue; 129 | 130 | // after that, order by similarity with the from url 131 | unsigned int pref_len = 0; 132 | while (pref_len < std::min(candidate.size(), from.size())) { 133 | if (candidate[pref_len] != from[pref_len]) 134 | break; 135 | pref_len++; 136 | } 137 | w += candidate.substr(0, pref_len).count('/') * 10; 138 | 139 | // and the smaller the path, the better 140 | w -= candidate.count('/'); 141 | 142 | if (w < weight) 143 | continue; 144 | 145 | weight = w; 146 | resolved = std::string(candidate); 147 | } 148 | return resolved; 149 | } 150 | -------------------------------------------------------------------------------- /generator/projectmanager.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright (C) 2012-2016 Woboq GmbH 3 | * Olivier Goffart 4 | * https://woboq.com/codebrowser.html 5 | * 6 | * This file is part of the Woboq Code Browser. 7 | * 8 | * Commercial License Usage: 9 | * Licensees holding valid commercial licenses provided by Woboq may use 10 | * this file in accordance with the terms contained in a written agreement 11 | * between the licensee and Woboq. 12 | * For further information see https://woboq.com/codebrowser.html 13 | * 14 | * Alternatively, this work may be used under a Creative Commons 15 | * Attribution-NonCommercial-ShareAlike 3.0 (CC-BY-NC-SA 3.0) License. 16 | * http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US 17 | * This license does not allow you to use the code browser to assist the 18 | * development of your commercial software. If you intent to do so, consider 19 | * purchasing a commercial licence. 20 | ****************************************************************************/ 21 | 22 | #pragma once 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | struct ProjectInfo 30 | { 31 | std::string name; 32 | std::string source_path; 33 | // std::string description; 34 | // std::string version_info; 35 | // std::string repo_url; //may contains tags; 36 | std::string revision; 37 | 38 | std::string external_root_url; 39 | 40 | // TODO 41 | std::string fileRepoUrl(const std::string &file) const 42 | { 43 | return {}; 44 | } 45 | enum Type { 46 | Normal, 47 | Internal, // includes and stuffs 48 | External, // links to external projects somewhere else, do not generate refs or anything, 49 | // and link to a different ref source 50 | } type = Normal; 51 | 52 | ProjectInfo(std::string name, std::string source_path, Type t = Normal) 53 | : name(std::move(name)) 54 | , source_path(std::move(source_path)) 55 | , type(t) 56 | { 57 | } 58 | ProjectInfo(std::string name, std::string source_path, std::string rev) 59 | : name(std::move(name)) 60 | , source_path(std::move(source_path)) 61 | , revision(std::move(rev)) 62 | { 63 | } 64 | }; 65 | 66 | struct ProjectManager 67 | { 68 | explicit ProjectManager(std::string outputPrefix, std::string _dataPath); 69 | 70 | bool addProject(ProjectInfo info); 71 | 72 | std::vector projects; 73 | 74 | std::string outputPrefix; 75 | std::string dataPath; 76 | 77 | // the file name need to be canonicalized 78 | ProjectInfo *projectForFile(llvm::StringRef filename); // don't keep a cache 79 | 80 | // return true if the filename should be proesseded. 81 | // 'project' is the value returned by projectForFile 82 | bool shouldProcess(llvm::StringRef filename, ProjectInfo *project) const; 83 | 84 | std::string includeRecovery(llvm::StringRef includeName, llvm::StringRef from); 85 | 86 | private: 87 | static std::vector systemProjects(); 88 | 89 | std::unordered_multimap includeRecoveryCache; 90 | }; 91 | -------------------------------------------------------------------------------- /generator/projectmanager_systemprojects.cpp.in: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright (C) 2018 Woboq GmbH 3 | * Dominik Schmidt 4 | * https://woboq.com/codebrowser.html 5 | * 6 | * This file is part of the Woboq Code Browser. 7 | * 8 | * Commercial License Usage: 9 | * Licensees holding valid commercial licenses provided by Woboq may use 10 | * this file in accordance with the terms contained in a written agreement 11 | * between the licensee and Woboq. 12 | * For further information see https://woboq.com/codebrowser.html 13 | * 14 | * Alternatively, this work may be used under a Creative Commons 15 | * Attribution-NonCommercial-ShareAlike 3.0 (CC-BY-NC-SA 3.0) License. 16 | * http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US 17 | * This license does not allow you to use the code browser to assist the 18 | * development of your commercial software. If you intent to do so, consider 19 | * purchasing a commercial licence. 20 | ****************************************************************************/ 21 | 22 | #include "projectmanager.h" 23 | 24 | #include 25 | 26 | std::vector ProjectManager::systemProjects() 27 | { 28 | std::vector projects; 29 | 30 | std::istringstream stream("@SYSTEM_INCLUDE_DIRS@"); 31 | std::string current; 32 | std::string name; 33 | 34 | while (std::getline(stream, current, ';')) { 35 | if(name.empty()) { 36 | name = current; 37 | } else { 38 | projects.emplace_back(name, current, ProjectInfo::Internal); 39 | name.clear(); 40 | } 41 | } 42 | 43 | return projects; 44 | } 45 | -------------------------------------------------------------------------------- /generator/qtsupport.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright (C) 2012-2016 Woboq GmbH 3 | * Olivier Goffart 4 | * https://woboq.com/codebrowser.html 5 | * 6 | * This file is part of the Woboq Code Browser. 7 | * 8 | * Commercial License Usage: 9 | * Licensees holding valid commercial licenses provided by Woboq may use 10 | * this file in accordance with the terms contained in a written agreement 11 | * between the licensee and Woboq. 12 | * For further information see https://woboq.com/codebrowser.html 13 | * 14 | * Alternatively, this work may be used under a Creative Commons 15 | * Attribution-NonCommercial-ShareAlike 3.0 (CC-BY-NC-SA 3.0) License. 16 | * http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US 17 | * This license does not allow you to use the code browser to assist the 18 | * development of your commercial software. If you intent to do so, consider 19 | * purchasing a commercial licence. 20 | ****************************************************************************/ 21 | 22 | /* This file handle the support of the SIGNAL and SLOT macro in QObject::connect */ 23 | 24 | #include "qtsupport.h" 25 | #include "annotator.h" 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | /** 35 | * Lookup candidates function of name \a methodName within the QObject derivative \a objClass 36 | * its bases, or its private implementation 37 | */ 38 | static llvm::SmallVector 39 | lookUpCandidates(const clang::CXXRecordDecl *objClass, llvm::StringRef methodName) 40 | { 41 | llvm::SmallVector candidates; 42 | clang::CXXMethodDecl *d_func = nullptr; 43 | auto classIt = objClass; 44 | while (classIt) { 45 | if (!classIt->getDefinition()) 46 | break; 47 | 48 | for (auto mi = classIt->method_begin(); mi != classIt->method_end(); ++mi) { 49 | if (!(*mi)->getIdentifier()) 50 | continue; 51 | if ((*mi)->getName() == methodName) 52 | candidates.push_back(*mi); 53 | if (!d_func && (*mi)->getName() == "d_func" && !getResultType(*mi).isNull()) 54 | d_func = *mi; 55 | } 56 | 57 | // Look in the first base (because the QObject need to be the first base class) 58 | classIt = classIt->getNumBases() == 0 59 | ? nullptr 60 | : classIt->bases_begin()->getType()->getAsCXXRecordDecl(); 61 | 62 | if (d_func && !classIt && candidates.empty()) { 63 | classIt = getResultType(d_func)->getPointeeCXXRecordDecl(); 64 | d_func = nullptr; 65 | } 66 | } 67 | return candidates; 68 | } 69 | 70 | /** 71 | * \a obj is an expression to a type of an QObject (or pointer to) that is the sender or the 72 | * receiver \a method is an expression like SIGNAL(....) or SLOT(....) 73 | * 74 | * This function try to find the matching signal or slot declaration, and register its use. 75 | */ 76 | void QtSupport::handleSignalOrSlot(clang::Expr *obj, clang::Expr *method) 77 | { 78 | if (!obj || !method) 79 | return; 80 | obj = obj->IgnoreImpCasts(); 81 | method = method->IgnoreImpCasts(); 82 | auto objType = obj->getType().getTypePtrOrNull(); 83 | if (!objType) 84 | return; 85 | 86 | const clang::CXXRecordDecl *objClass = objType->getPointeeCXXRecordDecl(); 87 | if (!objClass) { 88 | // It can be a non-pointer if called like: foo.connect(....); 89 | objClass = objType->getAsCXXRecordDecl(); 90 | if (!objClass) 91 | return; 92 | } 93 | 94 | const clang::StringLiteral *methodLiteral = clang::dyn_cast(method); 95 | if (!methodLiteral) { 96 | // try qFlagLocation 97 | clang::CallExpr *flagLoc = clang::dyn_cast(method); 98 | 99 | if (!flagLoc || flagLoc->getNumArgs() != 1 || !flagLoc->getDirectCallee() 100 | || flagLoc->getDirectCallee()->getName() != "qFlagLocation") 101 | return; 102 | 103 | 104 | methodLiteral = clang::dyn_cast(flagLoc->getArg(0)->IgnoreImpCasts()); 105 | if (!methodLiteral) 106 | return; 107 | } 108 | if (methodLiteral->getCharByteWidth() != 1) 109 | return; 110 | 111 | 112 | auto signature = methodLiteral->getString().trim(); 113 | if (signature.size() < 4) 114 | return; 115 | 116 | if (signature.find('\0') != signature.npos) { 117 | signature = signature.substr(0, signature.find('\0')).trim(); 118 | } 119 | 120 | auto lParenPos = signature.find('('); 121 | auto rParenPos = signature.find(')'); 122 | if (rParenPos == std::string::npos || rParenPos < lParenPos || lParenPos < 2) 123 | return; 124 | 125 | llvm::StringRef methodName = signature.slice(1, lParenPos).trim(); 126 | 127 | // Try to find the method which match this name in the given class or bases. 128 | auto candidates = lookUpCandidates(objClass, methodName); 129 | 130 | clang::LangOptions lo; 131 | lo.CPlusPlus = true; 132 | lo.Bool = true; 133 | clang::PrintingPolicy policy(lo); 134 | policy.SuppressScope = true; 135 | 136 | auto argPos = lParenPos + 1; 137 | unsigned int arg = 0; 138 | while (argPos < signature.size() && !candidates.empty()) { 139 | 140 | // Find next comma to extract the next argument 141 | auto searchPos = argPos; 142 | while (searchPos < signature.size() && signature[searchPos] != ',' 143 | && signature[searchPos] != ')') { 144 | if (signature[searchPos] == '<') { 145 | int depth = 0; 146 | int templDepth = 0; 147 | searchPos++; 148 | while (searchPos < signature.size() && depth >= 0 && templDepth >= 0) { 149 | switch (signature[searchPos]) { 150 | case '(': 151 | case '[': 152 | case '{': 153 | depth++; 154 | break; 155 | case ')': 156 | case ']': 157 | case '}': 158 | depth--; 159 | break; 160 | case '>': 161 | if (depth == 0) 162 | templDepth--; 163 | break; 164 | case '<': 165 | if (depth == 0) 166 | templDepth++; 167 | break; 168 | } 169 | ++searchPos; 170 | } 171 | continue; 172 | } 173 | ++searchPos; 174 | } 175 | 176 | if (searchPos == signature.size()) 177 | return; 178 | 179 | llvm::StringRef argument = signature.substr(argPos, searchPos - argPos).trim(); 180 | // Skip the const at the beginning 181 | 182 | if (argument.starts_with("const ") && argument.ends_with("&")) 183 | argument = argument.slice(6, argument.size() - 1).trim(); 184 | 185 | argPos = searchPos + 1; 186 | 187 | if (argument.empty() && signature[searchPos] == ')' && arg == 0) 188 | break; // No arguments 189 | 190 | 191 | // Now go over the candidates and prune the impossible ones. 192 | auto it = candidates.begin(); 193 | while (it != candidates.end()) { 194 | if ((*it)->getNumParams() < arg + 1) { 195 | // Not enough argument 196 | it = candidates.erase(it); 197 | continue; 198 | } 199 | 200 | auto type = (*it)->getParamDecl(arg)->getType(); 201 | 202 | // remove const or const & 203 | if (type->isReferenceType() && type.getNonReferenceType().isConstQualified()) 204 | type = type.getNonReferenceType(); 205 | type.removeLocalConst(); 206 | 207 | auto typeString_ = type.getAsString(policy); 208 | 209 | auto typeString = llvm::StringRef(typeString_).trim(); 210 | 211 | // Now compare the two string without mathcin spaces, 212 | auto sigIt = argument.begin(); 213 | auto parIt = typeString.begin(); 214 | while (sigIt != argument.end() && parIt != typeString.end()) { 215 | if (*sigIt == *parIt) { 216 | ++sigIt; 217 | ++parIt; 218 | } else if (*sigIt == ' ') { 219 | ++sigIt; 220 | } else if (*parIt == ' ') { 221 | ++parIt; 222 | } else if (*sigIt == 'n' && llvm::StringRef(sigIt, 9).starts_with("nsigned ")) { 223 | // skip unsigned 224 | sigIt += 8; 225 | } else if (*parIt == 'n' && llvm::StringRef(parIt, 9).starts_with("nsigned ")) { 226 | // skip unsigned 227 | parIt += 8; 228 | } else { 229 | break; 230 | } 231 | } 232 | 233 | if (sigIt != argument.end() || parIt != typeString.end()) { 234 | // Did not match. 235 | it = candidates.erase(it); 236 | continue; 237 | } 238 | 239 | ++it; 240 | } 241 | 242 | arg++; 243 | if (signature[searchPos] == ')') 244 | break; 245 | } 246 | 247 | if (argPos != signature.size()) 248 | return; 249 | 250 | 251 | // Remove candidates that needs more argument 252 | candidates.erase( 253 | std::remove_if(candidates.begin(), candidates.end(), 254 | [=](clang::CXXMethodDecl *it) { 255 | return it->getMinRequiredArguments() > arg 256 | && !(it->getNumParams() == arg + 1 257 | && it->getParamDecl(arg)->getType().getAsString(policy) 258 | == "QPrivateSignal"); 259 | }), 260 | candidates.end()); 261 | 262 | if (candidates.empty()) 263 | return; 264 | 265 | auto used = candidates.front(); 266 | 267 | 268 | 269 | clang::SourceRange range = methodLiteral->getSourceRange(); 270 | if (methodLiteral->getNumConcatenated() >= 2) { 271 | auto &sm = annotator.getSourceMgr(); 272 | // Goes two level up in the macro expension: First level is the # expansion, Second level 273 | // is SIGNAL macro 274 | auto r = sm.getImmediateExpansionRange(methodLiteral->getStrTokenLoc(1)); 275 | range = { sm.getImmediateExpansionRange(r.getBegin()).getBegin(), 276 | sm.getImmediateExpansionRange(r.getEnd()).getEnd() }; 277 | 278 | // now remove the SIGNAL or SLOT macro from the range. 279 | auto skip = clang::Lexer::MeasureTokenLength(range.getBegin(), sm, annotator.getLangOpts()); 280 | range.setBegin(range.getBegin().getLocWithOffset(skip + 1)); 281 | // remove the ')' while we are on it 282 | range.setEnd(range.getEnd().getLocWithOffset(-1)); 283 | } 284 | 285 | annotator.registerUse(used, range, Annotator::Call, currentContext, Annotator::Use_Address); 286 | } 287 | 288 | /** 289 | * Very similar to handleSignalOrSlot, but does not handle the fact that the string might be in a 290 | * macro and does the string contains the method name and not the full signature \a obj is an 291 | * expression to a type of an QObject (or pointer to) that is the sender or the receiver \a method 292 | * is an expression of type char* 293 | * 294 | * TODO: handle overloads 295 | */ 296 | void QtSupport::handleInvokeMethod(clang::Expr *obj, clang::Expr *method) 297 | { 298 | if (!obj || !method) 299 | return; 300 | obj = obj->IgnoreImpCasts(); 301 | method = method->IgnoreImpCasts(); 302 | auto objType = obj->getType().getTypePtrOrNull(); 303 | if (!objType) 304 | return; 305 | const clang::CXXRecordDecl *objClass = objType->getPointeeCXXRecordDecl(); 306 | if (!objClass) 307 | return; 308 | 309 | const clang::StringLiteral *methodLiteral = clang::dyn_cast(method); 310 | if (!methodLiteral) 311 | return; 312 | if (methodLiteral->getCharByteWidth() != 1) 313 | return; 314 | 315 | auto methodName = methodLiteral->getString(); 316 | if (methodName.empty()) 317 | return; 318 | 319 | // Try to find the method which match this name in the given class or bases. 320 | auto candidates = lookUpCandidates(objClass, methodName); 321 | if (candidates.size() != 1) 322 | return; 323 | // FIXME: overloads resolution using the Q_ARG 324 | 325 | auto used = candidates.front(); 326 | clang::SourceRange range = methodLiteral->getSourceRange(); 327 | annotator.registerUse(used, range, Annotator::Call, currentContext, Annotator::Use_Address); 328 | } 329 | 330 | void QtSupport::visitCallExpr(clang::CallExpr *e) 331 | { 332 | clang::CXXMethodDecl *methodDecl = 333 | clang::dyn_cast_or_null(e->getCalleeDecl()); 334 | if (!methodDecl || !methodDecl->getDeclName().isIdentifier() || !methodDecl->getParent()) 335 | return; 336 | if (!methodDecl->getParent()->getDeclName().isIdentifier()) 337 | return; 338 | 339 | auto parentName = methodDecl->getParent()->getName(); 340 | 341 | if (!parentName.starts_with("Q")) 342 | return; // only Qt classes 343 | 344 | if (parentName == "QObject" 345 | && (methodDecl->getName() == "connect" || methodDecl->getName() == "disconnect")) { 346 | // We have a call to QObject::connect or disconnect 347 | if (methodDecl->isStatic()) { 348 | if (e->getNumArgs() >= 4) { 349 | handleSignalOrSlot(e->getArg(0), e->getArg(1)); 350 | handleSignalOrSlot(e->getArg(2), e->getArg(3)); 351 | } 352 | } else if (clang::CXXMemberCallExpr *me = clang::dyn_cast(e)) { 353 | if (e->getNumArgs() >= 3) { 354 | handleSignalOrSlot(e->getArg(0), e->getArg(1)); 355 | handleSignalOrSlot(me->getImplicitObjectArgument(), e->getArg(2)); 356 | } 357 | } 358 | } 359 | if (parentName == "QTimer" && methodDecl->getName() == "singleShot") { 360 | if (e->getNumArgs() >= 3) { 361 | handleSignalOrSlot(e->getArg(1), e->getArg(2)); 362 | } 363 | } 364 | if (parentName == "QHostInfo" && methodDecl->getName() == "lookupHost") { 365 | if (e->getNumArgs() >= 3) { 366 | handleSignalOrSlot(e->getArg(1), e->getArg(2)); 367 | } 368 | } 369 | if (parentName == "QNetworkAccessCache" && methodDecl->getName() == "requestEntry") { 370 | if (e->getNumArgs() >= 3) { 371 | handleSignalOrSlot(e->getArg(1), e->getArg(2)); 372 | } 373 | } 374 | if (parentName == "QDBusAbstractInterface" && methodDecl->getName() == "callWithCallback") { 375 | if (e->getNumArgs() == 4) { 376 | handleSignalOrSlot(e->getArg(2), e->getArg(3)); 377 | } else if (e->getNumArgs() == 5) { 378 | handleSignalOrSlot(e->getArg(2), e->getArg(3)); 379 | handleSignalOrSlot(e->getArg(2), e->getArg(4)); 380 | } 381 | } 382 | if (methodDecl->getName() == "open" 383 | && (parentName == "QFileDialog" || parentName == "QColorDialog" 384 | || parentName == "QFontDialog" || parentName == "QMessageBox" 385 | || parentName == "QInputDialog" || parentName == "QPrintDialog" 386 | || parentName == "QPageSetupDialog" || parentName == "QPrintPreviewDialog" 387 | || parentName == "QProgressDialog")) { 388 | if (e->getNumArgs() == 2) { 389 | handleSignalOrSlot(e->getArg(0), e->getArg(1)); 390 | } 391 | } 392 | if (parentName == "QMenu" && methodDecl->getName() == "addAction") { 393 | if (methodDecl->getNumParams() == 4 && e->getNumArgs() >= 3) { 394 | handleSignalOrSlot(e->getArg(1), e->getArg(2)); 395 | } else if (methodDecl->getNumParams() == 5 && e->getNumArgs() >= 4) { 396 | handleSignalOrSlot(e->getArg(2), e->getArg(3)); 397 | } 398 | } 399 | if (parentName == "QToolbar" && methodDecl->getName() == "addAction") { 400 | if (e->getNumArgs() == 3) { 401 | handleSignalOrSlot(e->getArg(1), e->getArg(2)); 402 | } else if (e->getNumArgs() == 4) { 403 | handleSignalOrSlot(e->getArg(2), e->getArg(3)); 404 | } 405 | } 406 | if (parentName == "QState" && methodDecl->getName() == "addTransition") { 407 | if (e->getNumArgs() >= 2) { 408 | handleSignalOrSlot(e->getArg(0), e->getArg(1)); 409 | } 410 | } 411 | if (parentName == "QMetaObject" && methodDecl->getName() == "invokeMethod") { 412 | if (e->getNumArgs() >= 2) { 413 | handleInvokeMethod(e->getArg(0), e->getArg(1)); 414 | } 415 | } 416 | } 417 | 418 | void QtSupport::visitCXXConstructExpr(clang::CXXConstructExpr *e) 419 | { 420 | clang::CXXConstructorDecl *methodDecl = e->getConstructor(); 421 | if (!methodDecl || !methodDecl->getParent()) 422 | return; 423 | 424 | auto parent = methodDecl->getParent(); 425 | if (!parent->getName().starts_with("Q")) 426 | return; // only Qt classes 427 | 428 | if (parent->getName() == "QShortcut") { 429 | if (e->getNumArgs() >= 3) 430 | handleSignalOrSlot(e->getArg(1), e->getArg(2)); 431 | if (e->getNumArgs() >= 4) 432 | handleSignalOrSlot(e->getArg(1), e->getArg(3)); 433 | } 434 | if (parent->getName() == "QSignalSpy" || parent->getName() == "QSignalTransition") { 435 | if (e->getNumArgs() >= 2) { 436 | handleSignalOrSlot(e->getArg(0), e->getArg(1)); 437 | } 438 | } 439 | } 440 | -------------------------------------------------------------------------------- /generator/qtsupport.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright (C) 2012-2016 Woboq GmbH 3 | * Olivier Goffart 4 | * https://woboq.com/codebrowser.html 5 | * 6 | * This file is part of the Woboq Code Browser. 7 | * 8 | * Commercial License Usage: 9 | * Licensees holding valid commercial licenses provided by Woboq may use 10 | * this file in accordance with the terms contained in a written agreement 11 | * between the licensee and Woboq. 12 | * For further information see https://woboq.com/codebrowser.html 13 | * 14 | * Alternatively, this work may be used under a Creative Commons 15 | * Attribution-NonCommercial-ShareAlike 3.0 (CC-BY-NC-SA 3.0) License. 16 | * http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US 17 | * This license does not allow you to use the code browser to assist the 18 | * development of your commercial software. If you intent to do so, consider 19 | * purchasing a commercial licence. 20 | ****************************************************************************/ 21 | 22 | #pragma once 23 | 24 | namespace clang { 25 | class CallExpr; 26 | class NamedDecl; 27 | class Expr; 28 | class CXXConstructExpr; 29 | } 30 | class Annotator; 31 | 32 | 33 | /** 34 | * Handle the SIGNAL and SLOT macro within calls to QObject::connect or the like 35 | * 36 | * Recognize calls to QObject::connect, QObject::disconnect, QTimer::singleShot 37 | */ 38 | struct QtSupport 39 | { 40 | Annotator &annotator; 41 | clang::NamedDecl *currentContext; 42 | 43 | void visitCallExpr(clang::CallExpr *e); 44 | void visitCXXConstructExpr(clang::CXXConstructExpr *e); 45 | 46 | private: 47 | void handleSignalOrSlot(clang::Expr *obj, clang::Expr *method); 48 | void handleInvokeMethod(clang::Expr *obj, clang::Expr *method); 49 | }; 50 | -------------------------------------------------------------------------------- /generator/stringbuilder.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | struct string_builder_helper; 6 | 7 | template 8 | struct string_builder 9 | { 10 | typedef string_builder_helper HA; 11 | typedef string_builder_helper HB; 12 | operator std::string() const 13 | { 14 | std::string s; 15 | s.reserve(size()); 16 | HA::append_to(s, a); 17 | HB::append_to(s, b); 18 | return s; 19 | } 20 | unsigned int size() const 21 | { 22 | return HA::size(a) + HB::size(b); 23 | } 24 | 25 | string_builder(const A &a, const B &b) 26 | : a(a) 27 | , b(b) 28 | { 29 | } 30 | const A &a; 31 | const B &b; 32 | }; 33 | 34 | template<> 35 | struct string_builder_helper 36 | { 37 | typedef std::string T; 38 | static unsigned int size(const std::string &s) 39 | { 40 | return s.size(); 41 | } 42 | static void append_to(std::string &s, const std::string &a) 43 | { 44 | s += a; 45 | } 46 | }; 47 | 48 | template<> 49 | struct string_builder_helper 50 | { 51 | typedef const char *T; 52 | static unsigned int size(const char *s) 53 | { 54 | return std::strlen(s); 55 | } 56 | static void append_to(std::string &s, const char *a) 57 | { 58 | s += a; 59 | } 60 | }; 61 | 62 | template 63 | struct string_builder_helper> 64 | { 65 | typedef string_builder T; 66 | static unsigned int size(const T &t) 67 | { 68 | return t.size(); 69 | } 70 | static void append_to(std::string &s, const T &t) 71 | { 72 | T::HA::append_to(s, t.a); 73 | T::HB::append_to(s, t.b); 74 | } 75 | }; 76 | 77 | template 78 | struct string_builder_helper 79 | { 80 | typedef char T[N]; 81 | static unsigned int size(const char *s) 82 | { 83 | return N - 1; 84 | } 85 | static void append_to(std::string &s, const char *a) 86 | { 87 | s.append(a, N - 1); 88 | } 89 | }; 90 | 91 | template 92 | string_builder::T, typename string_builder_helper::T> 93 | operator%(const A &a, const B &b) 94 | { 95 | return { a, b }; 96 | } 97 | 98 | template 99 | std::string &operator%=(std::string &s, const T &t) 100 | { 101 | typedef string_builder_helper H; 102 | s.reserve(s.size() + H::size(t)); 103 | H::append_to(s, t); 104 | return s; 105 | } 106 | 107 | #include 108 | template<> 109 | struct string_builder_helper 110 | { 111 | typedef llvm::StringRef T; 112 | static unsigned int size(llvm::StringRef s) 113 | { 114 | return s.size(); 115 | } 116 | static void append_to(std::string &s, llvm::StringRef a) 117 | { 118 | s += a; 119 | } 120 | }; 121 | -------------------------------------------------------------------------------- /global.h: -------------------------------------------------------------------------------- 1 | 2 | #define CODEBROWSER_VERSION "2.1" 3 | -------------------------------------------------------------------------------- /indexgenerator/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(codebrowser_indexgenerator) 3 | add_executable(codebrowser_indexgenerator indexer.cpp) 4 | set_property(TARGET codebrowser_indexgenerator PROPERTY CXX_STANDARD 20) 5 | install(TARGETS codebrowser_indexgenerator RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) 6 | 7 | 8 | IF (APPLE) 9 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") 10 | SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++" ) 11 | ENDIF() 12 | -------------------------------------------------------------------------------- /indexgenerator/indexer.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright (C) 2012-2016 Woboq GmbH 3 | * Olivier Goffart 4 | * https://woboq.com/codebrowser.html 5 | * 6 | * This file is part of the Woboq Code Browser. 7 | * 8 | * Commercial License Usage: 9 | * Licensees holding valid commercial licenses provided by Woboq may use 10 | * this file in accordance with the terms contained in a written agreement 11 | * between the licensee and Woboq. 12 | * For further information see https://woboq.com/codebrowser.html 13 | * 14 | * Alternatively, this work may be used under a Creative Commons 15 | * Attribution-NonCommercial-ShareAlike 3.0 (CC-BY-NC-SA 3.0) License. 16 | * http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US 17 | * This license does not allow you to use the code browser to assist the 18 | * development of your commercial software. If you intent to do so, consider 19 | * purchasing a commercial licence. 20 | ****************************************************************************/ 21 | 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "../global.h" 32 | 33 | const char *data_url = "../data"; 34 | 35 | std::map > project_map; 36 | 37 | struct FolderInfo { 38 | // std::string name; 39 | std::map> subfolders; 40 | }; 41 | 42 | std::string extractMetaFromHTML(std::string metaName, std::string fullPath) { 43 | std::ifstream filein(fullPath, std::ifstream::in); 44 | std::string needle = "\n"; 46 | for (std::string line; std::getline(filein, line); ) { 47 | if (line.find(needle, 0) == 0) { 48 | return line.substr(needle.length(), line.length() - needle.length() - endneedle.length()); 49 | } 50 | } 51 | return ""; 52 | } 53 | 54 | std::string cutNameSpace(std::string &className) { 55 | int colonPos = className.find_last_of("::"); 56 | if (colonPos != std::string::npos) 57 | return className.substr(colonPos+1); 58 | else 59 | return className; 60 | } 61 | 62 | void linkInterestingDefinitions(std::ofstream &myfile, std::string linkFile, std::string &interestingDefitions) 63 | { 64 | if (interestingDefitions.length() == 0) { 65 | return; 66 | } 67 | myfile << ""; 82 | 83 | } 84 | 85 | void gererateRecursisively(FolderInfo *folder, const std::string &root, const std::string &path, const std::string &rel = "") { 86 | std::ofstream myfile; 87 | std::string filename = root + "/" + path + "index.html"; 88 | myfile.open(filename); 89 | if (!myfile) { 90 | std::cerr << "Error generating " << filename << std::endl; 91 | return; 92 | } 93 | std::cerr << "Generating " << filename << std::endl; 94 | 95 | std::string data_path = data_url[0] == '.' ? (rel + data_url) : std::string(data_url); 96 | 97 | 98 | size_t pos = root.rfind('/', root.size()-2); 99 | std::string project = pos < root.size() ? root.substr(pos+1) : root; 100 | std::string breadcrumb = "" +path + ""; 101 | std::string parent; 102 | 103 | pos = path.rfind('/', path.size()-2); 104 | if (pos < path.size()) { 105 | breadcrumb = "" + path.substr(pos+1)+ ""; 106 | 107 | unsigned int next_pos; 108 | while (pos > 0 && (next_pos = path.rfind('/', pos-1)) < path.size()) { 109 | if (pos != next_pos +1) { 110 | parent += "../"; 111 | breadcrumb = "" + path.substr(next_pos + 1, pos - next_pos - 1) + "/" + breadcrumb; 112 | } 113 | pos = next_pos; 114 | } 115 | if (pos > 1) { 116 | parent += "../"; 117 | breadcrumb = "" + path.substr(0, pos) + "/" + breadcrumb; 118 | } 119 | } 120 | if (path.length() > 0) { 121 | breadcrumb = "" + project + "/" + breadcrumb; 122 | } else { 123 | breadcrumb = "" + project + "/" + breadcrumb; 124 | } 125 | 126 | myfile << "\n" 127 | ""; 128 | myfile << project << "/" << path; 129 | myfile << " Source Tree - Woboq Code Browser\n" 130 | << "" 131 | "\n"; 132 | myfile << "\n"; 133 | myfile << "\n"; 134 | myfile << "\n" 135 | "\n" 136 | "\n\n"; 137 | myfile << "
\n"; 141 | 142 | //if (!path.empty()) 143 | { 144 | myfile << " \n"; 145 | } 146 | 147 | for (auto it : folder->subfolders) { 148 | const std::string &name = it.first; 149 | if (it.second) { 150 | gererateRecursisively(it.second.get(), root, path+name+"/", rel + "../"); 151 | myfile << "\n"; 153 | } else { 154 | std::string interestingDefintions = extractMetaFromHTML("woboq:interestingDefinitions", root + "/" + path + name + ".html"); 155 | myfile << "" 162 | << "\n"; 163 | } 164 | } 165 | 166 | char timebuf[80]; 167 | auto now = std::time(0); 168 | auto tm = std::localtime(&now); 169 | std::strftime(timebuf, sizeof(timebuf), "%Y-%b-%d", tm); 170 | 171 | myfile << "
../
[+] " 152 | "" << name << "/
" 156 | << name 157 | << "" 158 | << ""; 159 | linkInterestingDefinitions(myfile, name+".html", interestingDefintions); 160 | myfile << "" 161 | << "
" 172 | "
\n\n"; 184 | } 185 | 186 | int main(int argc, char **argv) { 187 | 188 | std::string root; 189 | bool skipOptions = false; 190 | 191 | for (int i = 1; i < argc; ++i) { 192 | std::string arg = argv[i]; 193 | if (!skipOptions && arg[0]=='-') { 194 | if (arg == "--") { 195 | skipOptions = true; 196 | } else if (arg=="-d") { 197 | i++; 198 | if (i < argc) 199 | data_url = argv[i]; 200 | } else if (arg=="-p") { 201 | i++; 202 | if (i < argc) { 203 | std::string s = argv[i]; 204 | auto colonPos = s.find(':'); 205 | if (colonPos >= s.size()) { 206 | std::cerr << "fail to parse project option : " << s << std::endl; 207 | continue; 208 | } 209 | auto secondColonPos = s.find(':', colonPos+1); 210 | if (secondColonPos < s.size()) { 211 | project_map[s.substr(0, colonPos)] = s.substr(secondColonPos + 1); 212 | } 213 | } 214 | } else if (arg=="-e") { 215 | i++; 216 | // ignore -e XXX for compatibility with the generator project definitions 217 | } 218 | } else { 219 | if (root.empty()) { 220 | root = arg; 221 | } else { 222 | root = ""; 223 | break; 224 | } 225 | } 226 | } 227 | 228 | if (root.empty()) { 229 | std::cerr << "Usage: " << argv[0] << " [-d data_url] [-p project_definition]" << std::endl; 230 | return -1; 231 | } 232 | std::ifstream fileIndex(root + "/" + "fileIndex"); 233 | std::string line; 234 | 235 | FolderInfo rootInfo; 236 | while (std::getline(fileIndex, line)) 237 | { 238 | FolderInfo *parent = &rootInfo; 239 | 240 | unsigned int pos = 0; 241 | unsigned int next_pos; 242 | while ((next_pos = line.find('/', pos)) < line.size()) { 243 | auto &sub = parent->subfolders[line.substr(pos, next_pos - pos)]; 244 | if (!sub) sub = std::make_shared(); 245 | parent = sub.get(); 246 | pos = next_pos + 1; 247 | } 248 | parent->subfolders[line.substr(pos)]; //make sure it exists; 249 | } 250 | gererateRecursisively(&rootInfo, root, ""); 251 | return 0; 252 | } 253 | -------------------------------------------------------------------------------- /scripts/fake_compiler.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | # 4 | # This script can be used to generate the compile_commands.json file. 5 | # Configure this script as the compiler, e.g. with the CC/CXX environment variables. 6 | # Export the $COMPILATION_COMMANDS environement variable to the full path of the compile_commands.json file. 7 | # set $FORWARD_COMPILER to the path of the actual compiler to perform the actual compilation. 8 | # 9 | # Example using configure (similar when using qmake): 10 | # 11 | # export COMPILATION_COMMANDS=/path/to/compile_commands.json 12 | # export FORWARD_COMPILER=g++ 13 | # CC=/path/to/fake_compiler.sh CXX=/path/to/fake_compiler.sh ./configure 14 | # echo "[" > $COMPILATION_COMMANDS 15 | # make -j1 16 | # echo " { \"directory\": \".\", \"command\": \"true\", \"file\": \"/dev/null\" } ]" >> $COMPILATION_COMMANDS 17 | 18 | 19 | directory=$PWD 20 | args=$@ 21 | file=`echo $args | sed 's/.* \([^ ]*\)/\1/'` 22 | new_file=`cd $directory && readlink -f $file 2>/dev/null | xargs echo -n` 23 | args=`echo $args | sed "s, -I\.\./, -I$directory/../,g" | sed "s, -I\. , -I$directory ,g" | sed "s, -I\./, -I$directory,g" | sed "s, -I\(/]\), -I$directory/\1,g" | sed 's,\\\\,\\\\\\\\,g' | sed 's/"/\\\\"/g'` 24 | echo "{ \"directory\": \"$directory\", \"command\": \"c++ $args\", \"file\": \"$new_file\" } , " >> $COMPILATION_COMMANDS 25 | 26 | if [ -z $FORWARD_COMPILER ]; then 27 | true 28 | else 29 | $FORWARD_COMPILER "$@" 30 | fi 31 | -------------------------------------------------------------------------------- /scripts/runner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # Derived from run-clang-tidy.py and adapted for Code Browser 4 | # See https://llvm.org/LICENSE.txt for license information of 5 | # the original file 6 | # 7 | import argparse 8 | import json 9 | import multiprocessing 10 | import os 11 | import shutil 12 | import subprocess 13 | import sys 14 | import threading 15 | from pathlib import Path 16 | import queue as queue 17 | from collections import OrderedDict 18 | import time 19 | 20 | suffix = "___suf" 21 | 22 | 23 | def make_absolute(f, directory): 24 | if os.path.isabs(f): 25 | return f 26 | return os.path.normpath(os.path.join(directory, f)) 27 | 28 | 29 | def generate(args, queue, lock, tid): 30 | while True: 31 | name = queue.get() 32 | cmd = [args.gen, "-b", args.compile_commands, "-o", args.out_dir] 33 | for project in args.projects: 34 | cmd.append("-p") 35 | cmd.append(project) 36 | if args.externalprojects is not None: 37 | for p in args.externalprojects: 38 | cmd.append("-e") 39 | cmd.append(p) 40 | 41 | cmd.append(name) 42 | 43 | my_env = os.environ.copy() 44 | my_env["MULTIPROCESS_MODE"] = suffix + str(tid) 45 | proc = subprocess.Popen( 46 | cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=my_env) 47 | output, err = proc.communicate() 48 | if proc.returncode != 0: 49 | if proc.returncode < 0: 50 | msg = "%s: terminated by signal %d\n" % ( 51 | name, -proc.returncode) 52 | err += msg.encode("utf-8") 53 | with lock: 54 | sys.stdout.write(" ".join(cmd) + "\n" + output.decode("utf-8")) 55 | if len(err) > 0: 56 | sys.stdout.flush() 57 | sys.stderr.write(err.decode("utf-8")) 58 | queue.task_done() 59 | 60 | 61 | def do_file(directory, f, max_task): 62 | # for a file name f 63 | # look for all f___suf[0 - max_task] 64 | # then merge them into one file and delete them 65 | # leaving only the merged file behind 66 | possible_files = list() 67 | for i in range(max_task): 68 | filepath = directory.joinpath(f + suffix + str(i)) 69 | if filepath.exists(): 70 | possible_files.append(filepath) 71 | 72 | txtlines = OrderedDict() 73 | for fil in possible_files: 74 | lines = str(fil.read_text()).splitlines() 75 | for line in lines: 76 | txtlines[line] = None 77 | 78 | txt = '\n'.join(txtlines.keys()) 79 | new_file = directory.joinpath(f) 80 | # print("create new file: {}".format(str(new_file))) 81 | new_file.write_text(txt) 82 | # remove old ones 83 | for fil in possible_files: 84 | fil.unlink() 85 | 86 | 87 | def do_merge_dir(d, max_task): 88 | dirPath = Path(d) 89 | files = set() 90 | for f in os.listdir(d): 91 | fn = os.fsdecode(f) 92 | try: 93 | if fn.index(suffix) != -1: 94 | files.add(fn.split(suffix)[0]) 95 | except ValueError: 96 | continue 97 | 98 | for f in files: 99 | do_file(dirPath, f, max_task) 100 | 101 | 102 | def do_merge(out, max_task): 103 | fnsearch = out + "/fnSearch" 104 | print("Merging ", fnsearch) 105 | do_merge_dir(fnsearch, max_task) 106 | 107 | refs = out + "/refs" 108 | print("Merging ", refs) 109 | do_merge_dir(refs, max_task) 110 | 111 | refsM = out + "/refs/_M" 112 | print("Merging ", refsM) 113 | do_merge_dir(refsM, max_task) 114 | 115 | print("Merging fileIndex") 116 | do_merge_dir(out, max_task) 117 | 118 | 119 | def main(): 120 | usage = "python runner.py -p compile_commands.json -o output/ -e ./generator/codebrowser_generator -a project_name -x external_project" 121 | parser = argparse.ArgumentParser( 122 | description="Runs codebrowser over all files in a compile_commands.json in parallel.", usage=usage) 123 | parser.add_argument("-j", type=int, default=0, 124 | help="number of generators to be run in parallel.") 125 | parser.add_argument( 126 | "-e", dest="gen", help="Path to codebrowser_generator.") 127 | parser.add_argument("-p", dest="compile_commands", 128 | help="Path to a compile_commands.json file.") 129 | parser.add_argument("-o", dest="out_dir", 130 | help="Path to output directory.") 131 | parser.add_argument("-a", dest="projects", action='extend', nargs='*', 132 | help="List of project names, source directory and version, specify as NAME:SOURCE_DIR:VERSION") 133 | parser.add_argument("-x", dest="externalprojects", action='extend', nargs='*', 134 | help="List of external project names, source directory and version, specify as project:path:url") 135 | 136 | args = parser.parse_args() 137 | 138 | compile_commands = args.compile_commands 139 | if compile_commands is None: 140 | print("Error: No compile commands specified") 141 | exit(1) 142 | 143 | if args.gen is None: 144 | print("Error: Please specify path to codebrowser_generator") 145 | exit(1) 146 | 147 | if args.projects is None: 148 | print("Error: Please specify at least one project") 149 | exit(1) 150 | 151 | if args.out_dir is None: 152 | print("Error: No output specified") 153 | exit(1) 154 | 155 | compile_commands = os.path.abspath(compile_commands) 156 | if not os.path.exists(compile_commands): 157 | print("Error: invalid path to compile_commands".format(compile_commands)) 158 | exit(1) 159 | 160 | print("using compile_commands.json: {}".format(compile_commands)) 161 | 162 | # Load the database and extract all files. 163 | database = json.load(open(compile_commands)) 164 | files = set( 165 | [make_absolute(entry["file"], entry["directory"]) 166 | for entry in database] 167 | ) 168 | 169 | max_task = args.j 170 | if max_task == 0: 171 | max_task = multiprocessing.cpu_count() 172 | 173 | try: 174 | task_queue = queue.Queue(max_task) 175 | # List of files with a non-zero return code. 176 | lock = threading.Lock() 177 | idx = 0 178 | for _ in range(max_task): 179 | t = threading.Thread( 180 | target=generate, args=(args, task_queue, lock, idx)) 181 | t.daemon = True 182 | t.start() 183 | idx = idx + 1 184 | 185 | # Fill the queue with files. 186 | for name in files: 187 | task_queue.put(name) 188 | 189 | # Wait for all threads to be done. 190 | task_queue.join() 191 | 192 | except KeyboardInterrupt: 193 | print("\nCtrl-C detected, goodbye.") 194 | if tmpdir: 195 | shutil.rmtree(tmpdir) 196 | os.kill(0, 9) 197 | 198 | print("Merging files...") 199 | start = time.time() 200 | 201 | do_merge(args.out_dir, max_task) 202 | 203 | end = time.time() 204 | print("Merged all files in: %.2F seconds" % (end - start)) 205 | 206 | sys.exit() 207 | 208 | 209 | if __name__ == "__main__": 210 | main() 211 | 212 | # kate: indent-width 4; replace-tabs on; 213 | -------------------------------------------------------------------------------- /scripts/woboq_cc.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* 3 | * This script can be used to generate the compile_commands.json file. 4 | * You need node.js to run this. 5 | * This script works as a fake compiler, whose partial name between "woboq_" and ".js" is used as the internal real compiler. 6 | * So you can symbolic link woboq_cc.js(cc) to woboq_clang++.js(clang++) or what ever compiler you need. 7 | * Example: 8 | * CC=/path/to/woboq_cc.js CXX=/path/to/woboq_c++.js ./configure 9 | * rm -rf $PWD/compile_commands.json 10 | * JSON_DIR=$PWD make -j1 11 | */ 12 | var fs = require('fs'), 13 | path = require('path'), 14 | child_process = require('child_process'); 15 | 16 | var jsonfile = process.env.JSON_DIR; 17 | if (jsonfile) { 18 | jsonfile = path.join(jsonfile, 'compile_commands.json'); 19 | } 20 | 21 | var argvs = process.argv; 22 | argvs.shift(); // remove "node" 23 | var scriptName = argvs.shift(); // remove "woboq_xx.js" and extract the "xx" 24 | var compiler = scriptName.match(/.*woboq_(.*?)\.js/)[1]; 25 | if (!compiler) { 26 | console.error("Can not extract the compiler name from script name " + scriptName); 27 | process.exit(1); 28 | } 29 | 30 | var srcfile = path.resolve(argvs.slice(-1).join()); 31 | fs.access(srcfile, fs.R_OK, (accerr) => { 32 | if (jsonfile && !accerr) { 33 | fs.readFile(jsonfile, function(err, data) { 34 | var compile_commands = []; 35 | if (!err) { 36 | try { 37 | compile_commands = JSON.parse(data); 38 | } catch(e) { 39 | // ignore it, later we will overwrite it 40 | } 41 | } 42 | compile_commands.push({ 43 | "directory" : process.cwd(), 44 | "command" : [compiler].concat(argvs).join(' '), 45 | "file" : srcfile 46 | }); 47 | fs.writeFileSync(jsonfile, JSON.stringify((compile_commands))); 48 | }); 49 | } 50 | }); 51 | 52 | child_process.spawnSync(compiler, argvs, { stdio: 'inherit' }); 53 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | project(tests) 3 | 4 | add_executable(tests test.cc) 5 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 6 | -------------------------------------------------------------------------------- /tests/doc.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | /** 6 | * \class DocMyClass 7 | * \brief the class 8 | * 9 | * @code 10 | * Here comes some code 11 | * * Continued 12 | * @endcode 13 | * 14 | * and a \c url 15 | * 16 | * some more description here, i should really write a lot 17 | * 18 | * Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet 19 | * ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec 20 | * et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam 21 | * tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula 22 | * ultricies a non tortor. Lorem ipsum dolor @c sit amet, consectetur adipiscing elit. Aenean ut 23 | * gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque 24 | * auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra 25 | * tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed 26 | * odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque 27 | * penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan 28 | * ultricies. Mauris vitae nisi at sem facilisis semper ac in est. 29 | * 30 | * Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. 31 | * In euismod ultrices facilisis. Vestibulum porta sapien adipiscing augue congue id pretium 32 | * lectus molestie. Proin quis dictum nisl. Morbi id quam sapien, sed vestibulum sem. Duis 33 | * elementum rutrum mauris sed convallis. Proin vestibulum magna mi. Aenean tristique hendrerit 34 | * magna, ac facilisis nulla hendrerit ut. Sed non tortor sodales quam auctor elementum. Donec 35 | * hendrerit nunc eget elit pharetra pulvinar. Suspendisse id tempus tortor. Aenean luctus, 36 | * elit commodo laoreet commodo, justo nisi consequat massa, sed vulputate quam urna quis eros. 37 | * Donec vel. 38 | * 39 | * \note foobar 40 | * 41 | * FIXME yoyo 42 | * @fixme fixme 43 | * @todo todo 44 | * 45 | */ 46 | 47 | int noDocumentationPlease(); 48 | 49 | class DocMyClass { 50 | private: void somePrivateMember(); 51 | protected: void someProtectedMember(); 52 | public: 53 | 54 | 55 | /** 56 | * \fn DocMyClass::somePrivateMember 57 | * private member 58 | */ 59 | /** 60 | * \fn DocMyClass::someProtectedMember 61 | * protected member 62 | */ 63 | 64 | virtual ~DocMyClass(); 65 | DocMyClass() : Buffer (0) {} ; 66 | 67 | /** 68 | * \fn DocMyClass::~DocMyClass 69 | * Destructor 70 | */ 71 | 72 | 73 | /** 74 | * \fn DocMyClass::DocMyClass 75 | * Constructor 76 | */ 77 | 78 | 79 | int fooOverload(); 80 | int fooOverload(int); 81 | 82 | int constOverload(int); 83 | int constOverload(int) const; 84 | 85 | /** 86 | * \fn DocMyClass::fooOverload() 87 | * A 88 | */ 89 | /** 90 | * \fn DocMyClass::fooOverload(int) 91 | * B 92 | */ 93 | /** 94 | * \fn DocMyClass::constOverload(int) 95 | * C 96 | */ 97 | /** 98 | * \fn DocMyClass::constOverload(int) const 99 | * D 100 | */ 101 | 102 | DocMyClass *returnPointer() { 103 | Capacity = 8; 104 | return nullptr; 105 | /** 106 | * \fn DocMyClass *DocMyClass::returnPointer(); 107 | * * 108 | */ 109 | } 110 | 111 | private: 112 | 113 | /// Doc for buffer; 114 | /// continued 115 | char *Buffer; 116 | 117 | /* doc for capacity */ 118 | int Capacity; 119 | 120 | // doc for index 121 | int Index; 122 | }; 123 | 124 | 125 | /* 126 | * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 127 | * <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 128 | * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 129 | * <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 130 | * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 131 | * <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 132 | * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 133 | * <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 134 | * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 135 | * <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 136 | * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 137 | * <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 138 | * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 139 | * <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 140 | * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 141 | * <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 142 | * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 143 | * <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 144 | * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 145 | * <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 146 | * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 147 | * <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 148 | * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 149 | * <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 150 | */ 151 | int wow; 152 | 153 | 154 | template 155 | class SuperList { 156 | public: 157 | SuperList(); 158 | SuperList(T); 159 | SuperList(int, int); 160 | ~SuperList(); 161 | int at(int); 162 | }; 163 | 164 | /*! \class SuperList */ 165 | 166 | /*! \fn SuperList::SuperList() */ 167 | /*! \fn SuperList::SuperList(T) */ 168 | /*! \fn SuperList::at */ 169 | 170 | 171 | enum DocumentedEnum { 172 | A, Hello, Yolla 173 | }; 174 | 175 | /*! \enum DocumentedEnum 176 | * \value A some value 177 | * \value Hello this is some other value that is verry interesting so the text is a 178 | * bit logner but it's still one 179 | * \value Yolla that's another value 180 | * 181 | * and here some more text about the enum 182 | */ -------------------------------------------------------------------------------- /tests/test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "notexist.g" 5 | 6 | #include "doc.h" 7 | 8 | 9 | namespace NS { 10 | namespace Foo { 11 | namespace Bar { 12 | typedef int Type; 13 | 14 | class T { 15 | int m( T *t) { 16 | t->Foo::Bar::T::~T(); 17 | } 18 | }; 19 | } 20 | } 21 | } 22 | 23 | using namespace NS::Foo::Bar; 24 | using namespace NS; 25 | 26 | /* comment 1 (NOT doc) */ /* comment 2 (NOT doc) */ 27 | struct MyBase { 28 | /* comment 3 (NOT doc) */ 29 | /* comment 4 (doc) */ 30 | Type member; 31 | static Type static_member; 32 | MyBase(); 33 | 34 | virtual ~MyBase() = default; 35 | }; 36 | 37 | MyBase::MyBase() { } 38 | 39 | /* here is a static member */ 40 | Type MyBase::static_member = 8; 41 | 42 | // documentation for MyClass begin { 43 | 44 | // } end 45 | struct MyClass /* ??? */ : MyBase { 46 | 47 | XXXXX undefined_type; 48 | 49 | std::string string; /// documentation for string 50 | std::string string2; /** and for string 2 */ /* more on string 2 */ 51 | 52 | union { 53 | //this is an integer 54 | /*!and this */ int integer; // plop 55 | // plop 56 | /* what is this */ double dbl; 57 | }; 58 | 59 | MyClass() : 60 | MyBase() , // type 61 | string("hello"), //member 62 | dbl(0.6) //ref 63 | { member = 3; //member 64 | bool a, b, c, d, e, f, g, h, i, j, k, l; 65 | } 66 | 67 | ~ MyClass(); 68 | 69 | static std::string function(int hi, 70 | bool ho, 71 | double = 4 + 5, 72 | std::string nothiung = std::string("hell") + "0" ) 73 | { return MyClass().string2; } 74 | 75 | virtual std::string m() const { 76 | std::string local = string; 77 | return function(1,2,2); 78 | } 79 | 80 | inline int hey() { 81 | return m().size(); 82 | } 83 | 84 | int outofline(std::string foo); 85 | 86 | operator std::string() const { return m(); } 87 | }; 88 | 89 | /** 90 | * Regression for getFieldOffset(), founded during processing `struct _IO_FILE` 91 | */ 92 | struct ForwardDeclareWillBeDeclaredAfter; 93 | struct ForwardDeclareWillBeDeclaredAfter 94 | { 95 | int mustBailHere; 96 | }; 97 | 98 | //http://code.woboq.org this is an url 99 | 100 | /*! 101 | * yo 102 | * @param foo bar foo 103 | * 104 | * yo 105 | * 106 | * @code 107 | * foo bar foo 108 | * @endcode 109 | * 110 | * @c hello world @c{yoyo m} 111 | * @li djq skql qslk 112 | * 113 | * dsd 114 | * 115 | * (https://woboq.com/) 116 | * visit https://woboq.com/blog. 117 | * https://en.wikipedia.org/wiki/Qt_(software) 118 | * 119 | */ 120 | 121 | int MyClass::outofline(std::string foo) 122 | { 123 | return foo.size(); 124 | } 125 | 126 | MyClass::~ /* random comment */ MyClass() 127 | { 128 | 129 | } 130 | 131 | ///Some enum 132 | /// @brief Just an enum 133 | 134 | enum MyEnum { Val1, //comment1 135 | //comment2 136 | Val2 = 3 + 3 }; 137 | MyEnum e = Val2; 138 | 139 | class Annotator; 140 | 141 | #define DECLARE_FUNCTION(TYPE, NAME, ARG1) TYPE NAME (ARG1) 142 | 143 | #define myMacro(MOO) MOO 144 | 145 | //Some macro 146 | DECLARE_FUNCTION(MyEnum, yoyo, MyClass&a) { 147 | 148 | myMacro(a.m()); 149 | return a.member ? 150 | Val1 : 151 | Val2; 152 | } 153 | 154 | int function() { 155 | struct { 156 | int m = 5; 157 | int operator +( 158 | int i) { 159 | return i+m; 160 | } 161 | }foo; 162 | 163 | return foo 164 | + //FIXME 165 | foo.m; 166 | } 167 | 168 | extern __typeof (function) function_alias1 __attribute__ ((weak, alias ("function"))); 169 | extern __typeof (function) function_alias2 __attribute__ ((alias ("function"))); 170 | 171 | std::string toString() { 172 | function(); 173 | function_alias1(); 174 | function_alias2(); 175 | MyClass c; 176 | c.function(noDocumentationPlease(), !c.outofline(std::string("T")), MyEnum::Val1, toString()); 177 | #define STRIGNIFY(X) #X 178 | return STRIGNIFY(true && "hello \"world\"") 179 | } 180 | 181 | int hasOwnProperty() { 182 | function() 183 | + function(); 184 | std::string foo("GHG"); 185 | return hasOwnProperty(); 186 | } 187 | 188 | 189 | struct MyClassDerived : MyClass { 190 | virtual std::string m() const override; 191 | }; 192 | 193 | std::string MyClassDerived::m() const 194 | { 195 | extern int* oh(); 196 | oh(); 197 | return MyClass::m(); 198 | } 199 | 200 | #define BUILD_NS(A, B) A::B 201 | #define BUILD_NS2(A, B) ::A::B 202 | BUILD_NS(NS::Foo::Bar , Type) tst_mac1; 203 | BUILD_NS2(NS::Foo::Bar , Type) tst_mac2; 204 | BUILD_NS(NS::Foo, Bar::Type) tst_mac3; 205 | NS::BUILD_NS(Foo, Bar)::Type tst_mac4; 206 | NS BUILD_NS2(Foo, Bar)::Type tst_mac5; 207 | 208 | void test_macros() { 209 | typedef int TTFoo; 210 | TTFoo a; 211 | #define TTFoo char 212 | TTFoo b; 213 | #undef TTFoo 214 | TTFoo c; 215 | }; 216 | 217 | //DECLARE_SOMETHING Macro 218 | #define DECLARE_SOMETHING(WHAT) WHAT mySomething \ 219 | { int foo(int a); } 220 | 221 | /* This is mySomething struct */ 222 | DECLARE_SOMETHING(struct); 223 | 224 | int mySomething::foo(int a) { 225 | return a; 226 | } 227 | 228 | 229 | namespace { 230 | /* class 231 | that is annonymus */ 232 | struct InAnonymousNamspace { 233 | int someFunction(); 234 | /* member 235 | * doc */ 236 | int member; 237 | }; 238 | } 239 | 240 | /* doc 241 | */ 242 | int InAnonymousNamspace::someFunction() 243 | { 244 | return member; 245 | } 246 | /** 247 | * @deprecated foobar 248 | * 249 | */ 250 | 251 | static int some_static_func() { 252 | extern int extern_val; 253 | static int local_static; 254 | InAnonymousNamspace a; 255 | local_static ++; 256 | return a.someFunction() + extern_val + local_static; 257 | } 258 | 259 | static int static_val; 260 | int nonstatic_val; 261 | 262 | int *oh() { 263 | extern int extern_val; 264 | goto label; 265 | nonstatic_val += extern_val; 266 | static_val += some_static_func(); 267 | label: 268 | int q = [&]() { 269 | extern_val++; 270 | static_val++; 271 | nonstatic_val++; 272 | label: 273 | static std::string local_static; 274 | local_static = "hello"; 275 | int loc = 4; 276 | struct MyStruct : MyBase { 277 | void operator+=(int q) { 278 | label: 279 | static_member += q; 280 | goto label; 281 | } 282 | /* that's magic */ 283 | int foo() { return 4; } 284 | }; 285 | 286 | goto label; 287 | MyStruct s; 288 | goto label; 289 | s+=loc; 290 | return loc + s.foo(); 291 | }(); 292 | if (q) { 293 | goto label; 294 | return &extern_val; 295 | } 296 | return &nonstatic_val; 297 | } 298 | 299 | class ForwardDeclare; 300 | int func() { 301 | ForwardDeclare thisIsAnError(34); 302 | } 303 | 304 | struct ClassWithForward { 305 | ForwardDeclare anotherError; 306 | }; 307 | int func2() { 308 | ClassWithForward yo; 309 | } 310 | 311 | 312 | #if 1 313 | 314 | #if false && \ 315 | true && false 316 | int foo_a; 317 | #elif truee && false 318 | int foo_r; 319 | #else 320 | int foo_d; 321 | #endif 322 | int foo_b: 323 | #endif 324 | #if some 325 | 326 | #endif 327 | 328 | #endif 329 | 330 | 331 | namespace rel_ops = std::rel_ops; 332 | 333 | 334 | extern int value; 335 | struct Val { int v; 336 | void operator+=(const Val &); 337 | } valval; 338 | const Val operator+(const Val&, const Val&); 339 | struct Uses { 340 | void operator[](int); 341 | void refFunc(int&); 342 | int hello; 343 | Val hello2; 344 | Uses(int i) : hello(value), hello2({valval.v}) {} 345 | int r() { 346 | auto v = value; 347 | v = value; 348 | v = { value }; 349 | v = Uses{value}.hello; 350 | long v2 = value; 351 | Val vvv = valval; 352 | vvv = valval; 353 | vvv = hello2; 354 | (*this)[value]; 355 | while(value) { } 356 | return value; 357 | } 358 | int w() { 359 | Val q; 360 | valval = q + q; 361 | q.v = 4; 362 | (&q)->v = 45 + 45; 363 | hello = 4; 364 | hello2 = Val() + Val(); 365 | Uses *u = this; 366 | u->hello2 = Val() + Val(); 367 | (*u).hello2 = Val() + Val(); 368 | hello2 += Val() + Val(); 369 | value = 2; 370 | value += 2; 371 | value++; 372 | ++value; 373 | switch(0) { case 0: value = 1; } 374 | return 12; 375 | } 376 | int &a() { 377 | auto *val = &valval; 378 | auto &v1 = value; 379 | auto v2 = &value; 380 | int &v3 { value }; 381 | auto &xx = (&valval)->v; 382 | auto *hi = &hello; 383 | refFunc(value); 384 | return value; 385 | } 386 | void o() { 387 | (void) value; 388 | } 389 | }; 390 | 391 | int &func(int &x, int &y) 392 | { return x == 1 ? func(y, func(y, func(y, x))) : x; } 393 | 394 | namespace SUPERlongNAMeSpace12345679814563efrqslkdjfq__hsdqsfsdqsdfqdsfqsdfqsdfqsdfgsgfhfjhsgs { 395 | 396 | template struct Long123456789123456789123456789FIFI { 397 | enum ValSUPERLdfqsdfqsdfqsdfqsdfqdfqsdfqsdfqsdfqsdfqsdfqsdf { Plop = sizeof(T) }; 398 | 399 | template std::vector FuncLong12345678912345678912345678 (const T2&) { 400 | return {}; 401 | } 402 | 403 | ValSUPERLdfqsdfqsdfqsdfqsdfqdfqsdfqsdfqsdfqsdfqsdfqsdf dsqsdqsdfqsdfkjlqsdflkqhsdflkqhsdflkqjhsdflkqjhsdflqkjhsflkqsjdlk; 404 | }; 405 | 406 | int testLong() { 407 | Long123456789123456789123456789FIFI>>> ff; 408 | ff.FuncLong12345678912345678912345678( &Long123456789123456789123456789FIFI::FuncLong12345678912345678912345678 ); 409 | 410 | ff.FuncLong12345678912345678912345678(ff.dsqsdqsdfqsdfkjlqsdflkqhsdflkqhsdflkqjhsdflkqjhsdflqkjhsflkqsjdlk); 411 | } 412 | 413 | } 414 | 415 | namespace issue_81 { 416 | 417 | // declaration of the template 418 | template struct container { 419 | container(T t) {} 420 | template container(Iter beg, Iter end){}; 421 | }; 422 | // additional deduction guide 423 | template 424 | container(Iter b, Iter e) -> container::value_type>; 425 | // uses 426 | 427 | int main(){ 428 | container c(7); // OK: deduces T=int using an implicitly-generated guide 429 | std::vector v = { /* ... */}; 430 | auto d = container(v.begin(), v.end()); // OK: deduces T=double 431 | } 432 | } 433 | -------------------------------------------------------------------------------- /tests/testqt.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class MyObjectPrivate { 5 | public: 6 | void myPrivateSlot(); 7 | }; 8 | 9 | class MyObject : public QObject { 10 | Q_OBJECT 11 | Q_DECLARE_PRIVATE(MyObject) 12 | public slots: 13 | 14 | void superSlot1(const QString &myString, const uint s); 15 | 16 | // this slot can be connected to everythinig 17 | void superSlot2(void * = nullptr); 18 | 19 | void anotherSlot(const QString &str1, unsigned int i1, const QMap &map); 20 | 21 | signals: 22 | // this one contains unsigned 23 | void mySignal1(const QString &str1, unsigned int i1, const QMap &map); 24 | 25 | // with a default argument 26 | void mySignal2(QString, uint c = 0); 27 | 28 | void pointerSignal(const QObject *); 29 | 30 | void myBoolSignal(bool); 31 | 32 | // void invalidSignal(InvalidTypeGoesHere); 33 | 34 | void downloadMetaData(QList >,int,QString,bool,QSharedPointer,qint64); 35 | 36 | public: 37 | QPainter *p; 38 | 39 | }; 40 | 41 | 42 | void MyObject::superSlot1(const QString& myString, const uint s) 43 | { 44 | MyObject stackOj; 45 | connect(&stackOj, SIGNAL(mySignal1(QString, uint ,QMap)), SLOT(anotherSlot(QString,uint,QMap))); 46 | 47 | connect(&stackOj, SIGNAL(mySignal2( const QString & ,uint)), this, SLOT(superSlot1( const QString &, const unsigned int & ))); 48 | 49 | connect(this, SIGNAL ( destroyed(QObject*) ), this, SLOT(superSlot2())); 50 | 51 | stackOj.connect(this, SIGNAL(mySignal1(QString,uint,QMap)), SLOT(superSlot1(QString,uint))); 52 | 53 | connect(this, SIGNAL(pointerSignal(const QObject*)) ,this, SLOT(myPrivateSlot())); 54 | connect(this, SIGNAL(myBoolSignal(bool)) ,this, SLOT(deleteLater())); 55 | connect(this, SIGNAL(downloadMetaData(QList >,int,QString,bool,QSharedPointer,qint64)), 56 | this, SLOT(deleteLater())); 57 | 58 | QMetaObject::invokeMethod(this, "superSlot1", Q_ARG(QString, "123"), Q_ARG(uint,5)); 59 | QMetaObject::invokeMethod(&stackOj, "superSlot2"); 60 | } 61 | 62 | 63 | #define DO( _, X ) X 64 | 65 | #define CONNECT connect(sender(), SIGNAL(objectNameChanged(QString)), qApp, SLOT(quit())) 66 | 67 | void MyObject::superSlot2(void*) 68 | { 69 | QTimer::singleShot(154, this, SLOT(superSlot2())); 70 | 71 | DO( _, connect(sender(), SIGNAL( destroyed(QObject*)), qApp, SLOT(quit())) ); 72 | 73 | CONNECT; 74 | 75 | QSignalSpy s(qApp, SIGNAL(applicationNameChanged())); 76 | } 77 | 78 | 79 | void MyObject::anotherSlot(const QString& str1, unsigned int i1, const QMap< int, QString >& map) 80 | { 81 | QScopedPointer t(new QTimer); 82 | 83 | connect(t.data(), SIGNAL(timeout()), &*t, SLOT(start())); 84 | 85 | t->connect(this, SIGNAL(destroyed(QObject*)), SLOT(stop())); 86 | 87 | t->connect(this, SIGNAL(invalidSignal(ErrorType)), SLOT(deletaLater())); 88 | 89 | disconnect(this, SIGNAL(mySignal1(QString,uint,QMap)), 0, 0); 90 | 91 | disconnect(this, SIGNAL(pointerSignal(const QObject*)), 0, 0); 92 | } 93 | 94 | 95 | class OverLoadTest : public QObject { 96 | Q_OBJECT 97 | signals: 98 | void ovr(int = 4); 99 | void ovr(const QString &); 100 | void ovr(const QString &, int); 101 | 102 | public slots: 103 | void doThings() { 104 | connect(this, SIGNAL(ovr()), this, SLOT(doThings())); 105 | connect(this, SIGNAL(ovr(int)), this, SLOT(doThings())); 106 | connect(this, SIGNAL(ovr(QString)), this, SLOT(doThings())); 107 | connect(this, SIGNAL(ovr(QString, int)), this, SLOT(doThings())); 108 | connect(this, SIGNAL(ovr(QString*)), this, SLOT(doThings())); //error on purpose 109 | } 110 | }; 111 | 112 | class OverrideTest : public OverLoadTest { 113 | signals: 114 | void ovr(int); // from reimpl 115 | 116 | public slots: 117 | void doThings(int = 4) { 118 | connect(this, SIGNAL(ovr()), this, SLOT(doThings())); //ovr should NOT be from reimpl 119 | connect(this, SIGNAL(ovr(int)), this, SLOT(doThings(int))); // should be from reimpl 120 | connect(this, SIGNAL(ovr(QString)), this, SLOT(doThings())); 121 | connect(this, SIGNAL(ovr(QString, int)), this, SLOT(doThings())); 122 | connect(this, SIGNAL(ovr(QString*)), this, SLOT(doThings())); //error on purpose 123 | } 124 | }; 125 | 126 | 127 | namespace TestNS { 128 | 129 | class C : public QObject { 130 | Q_OBJECT 131 | signals: 132 | void sig1(C *foo); 133 | void sig2(TestNS::C *foo); 134 | public slots: 135 | void MySlot() { 136 | connect(this, SIGNAL(sig1(C*)), this, SLOT(deleteLater())); 137 | connect(this, SIGNAL(sig2(TestNS::C*)), this, SLOT(deleteLater())); 138 | } 139 | }; 140 | 141 | } 142 | 143 | int ndbug(TestNS::C *c) { 144 | #define S1GNAL(X) "2" #X 145 | #define SL0T(X) "1" #X 146 | QObject::connect(c, S1GNAL(sig2(TestNS::C*)), c, SL0T(MySlot())); 147 | } 148 | 149 | 150 | class QQQQQ { 151 | public: 152 | void operator+(int) {} 153 | }; 154 | void dontcrash() { 155 | QQQQQ q; q + 4; 156 | } 157 | --------------------------------------------------------------------------------