From 3d5fe154f890d83e4e895dc87db48e1aeee625ed Mon Sep 17 00:00:00 2001 From: Siket Peter Date: Tue, 3 May 2022 16:04:11 +0200 Subject: [PATCH] Release version 5.0.0 --- .gitmodules | 15 +- 3rdparty/CMakeLists.txt | 112 +- 3rdparty/clang | 1 + 3rdparty/cppcheck | 1 + 3rdparty/miniz | 1 + CMake/AddExecutablePermission.cmake | 10 + CMake/BuildInfo.cmake | 5 + CMake/Clang.cmake | 39 + CMake/CodebaseOptions.cmake | 8 +- CMake/PlatformOptions.cmake | 29 +- CMake/UtilityFunctions.cmake | 50 +- CMakeLists.txt | 34 +- OpenStaticAnalyzer/CMakeLists.txt | 2 + OpenStaticAnalyzer/cpp/CMakeLists.txt | 124 + OpenStaticAnalyzer/cpp/demo/analyze.bat | 4 + OpenStaticAnalyzer/cpp/demo/analyze.sh | 3 + OpenStaticAnalyzer/cpp/demo/build-win-x64.bat | 5 + OpenStaticAnalyzer/cpp/demo/build.sh | 11 + .../cpp/demo/log4cplus-1.1.0.zip | Bin 0 -> 903303 bytes OpenStaticAnalyzer/cpp/demo/softfilter-linux | 2 + .../cpp/demo/softfilter-windows | 2 + .../cpp/doc/usersguide/CMakeLists.txt | 14 + .../cpp/doc/usersguide/img/structure.png | Bin 0 -> 89509 bytes .../cpp/doc/usersguide/md/ClangTidyRef.md | 9961 ++++++++++++++ .../md/CodeDuplicationMetricsRef.md | 152 + .../cpp/doc/usersguide/md/CppcheckRef.md | 1363 ++ .../cpp/doc/usersguide/md/Footnotes.md | 3 + .../cpp/doc/usersguide/md/Main.md | 580 + .../doc/usersguide/md/SourceCodeMetricsRef.md | 533 + .../cpp/doc/usersguide/md/WrappingTips.md | 202 + OpenStaticAnalyzer/csharp/CMakeLists.txt | 6 +- .../csharp/doc/usersguide/md/Main.md | 14 +- .../doc/usersguide/md/SourceCodeMetricsRef.md | 94 - OpenStaticAnalyzer/doc/readme.txt | 8 +- OpenStaticAnalyzer/java/CMakeLists.txt | 6 +- .../java/doc/usersguide/md/Main.md | 6 +- .../doc/usersguide/md/SourceCodeMetricsRef.md | 277 +- OpenStaticAnalyzer/javascript/CMakeLists.txt | 11 +- .../javascript/doc/usersguide/md/ESLintRef.md | 343 +- .../javascript/doc/usersguide/md/Main.md | 24 +- .../doc/usersguide/md/SourceCodeMetricsRef.md | 32 - OpenStaticAnalyzer/python/CMakeLists.txt | 6 +- .../python/doc/usersguide/md/Main.md | 2 +- .../doc/usersguide/md/SourceCodeMetricsRef.md | 80 +- README.md | 18 +- cl/CAN/CMakeLists.txt | 10 + cl/CAN/src/main.cpp | 302 + cl/CAN2Lim/CMakeLists.txt | 23 + cl/CAN2Lim/inc/ASTConversionInfo.h | 222 + cl/CAN2Lim/inc/ASTVisitor.h | 270 + cl/CAN2Lim/inc/CommentProcessor.h | 51 + cl/CAN2Lim/inc/Linker.h | 110 + cl/CAN2Lim/inc/MergeUID.h | 139 + cl/CAN2Lim/inc/clangHelpers.h | 56 + cl/CAN2Lim/inc/messages.h | 97 + cl/CAN2Lim/src/ASTConversionInfo.cpp | 210 + cl/CAN2Lim/src/ASTVisitor.cpp | 3136 +++++ cl/CAN2Lim/src/CommentProcessor.cpp | 280 + cl/CAN2Lim/src/Linker.cpp | 244 + cl/CAN2Lim/src/MergeUID.cpp | 450 + cl/CAN2Lim/src/clangHelpers.cpp | 110 + cl/CAN2Lim/src/main.cpp | 529 + cl/CANConfig/CMakeLists.txt | 12 + cl/CANConfig/main.cpp | 416 + cl/CANConfig/messages.h | 33 + cl/CANLib/CMakeLists.txt | 12 + cl/CANLib/inc/messages.h | 35 + cl/CANLib/src/main.cpp | 461 + cl/CANLink/CMakeLists.txt | 12 + cl/CANLink/inc/messages.h | 99 + cl/CANLink/src/main.cpp | 162 + cl/ClangTidy2Graph/CMakeLists.txt | 18 + cl/ClangTidy2Graph/ClangTidy.rul | 8562 ++++++++++++ cl/ClangTidy2Graph/inc/ResultConverter.h | 170 + cl/ClangTidy2Graph/inc/defines.h | 89 + cl/ClangTidy2Graph/inc/messages.h | 34 + cl/ClangTidy2Graph/rules.csv | 419 + cl/ClangTidy2Graph/src/ResultConverter.cpp | 373 + cl/ClangTidy2Graph/src/main.cpp | 222 + cl/Cppcheck2Graph/CMakeLists.txt | 21 + cl/Cppcheck2Graph/Cppcheck.rul | 6044 ++++++++ cl/Cppcheck2Graph/errorgroups.xml | 410 + cl/Cppcheck2Graph/errorlist.xml | 529 + cl/Cppcheck2Graph/inc/ResultConverter.h | 126 + cl/Cppcheck2Graph/inc/RuleConverter.h | 74 + cl/Cppcheck2Graph/inc/XMLParser.h | 51 + cl/Cppcheck2Graph/inc/defines.h | 88 + cl/Cppcheck2Graph/inc/messages.h | 35 + cl/Cppcheck2Graph/listerrors.xslt | 11 + cl/Cppcheck2Graph/options.csv | 298 + cl/Cppcheck2Graph/src/ResultConverter.cpp | 249 + cl/Cppcheck2Graph/src/RuleConverter.cpp | 307 + cl/Cppcheck2Graph/src/XMLParser.cpp | 81 + cl/Cppcheck2Graph/src/main.cpp | 164 + cl/DCF-CPP/CMakeLists.txt | 40 + cl/DCF-CPP/inc/AbstractFilter.h | 51 + .../DCF-CPP/inc/Aligner.h | 16 +- cl/DCF-CPP/inc/CPPNamedVisitor.h | 206 + cl/DCF-CPP/inc/CloneLengthFilter.h | 42 + cl/DCF-CPP/inc/CloneOccuranceFilter.h | 44 + cl/DCF-CPP/inc/ClonePositioned.h | 122 + cl/DCF-CPP/inc/Config.h | 125 + cl/DCF-CPP/inc/CppSerializeAST.h | 226 + cl/DCF-CPP/inc/DistanceVisitor.h | 117 + cl/DCF-CPP/inc/Interval.h | 82 + cl/DCF-CPP/inc/LanguageFactory.h | 65 + cl/DCF-CPP/inc/RepeatingLinesFilter.h | 46 + cl/DCF-CPP/inc/StatementFilter.h | 39 + cl/DCF-CPP/inc/Types.h | 95 + cl/DCF-CPP/inc/dcm.h | 828 ++ cl/DCF-CPP/inc/messages.h | 154 + cl/DCF-CPP/src/AbstractFilter.cpp | 28 + cl/DCF-CPP/src/CloneLengthFilter.cpp | 30 + cl/DCF-CPP/src/ClonePositioned.cpp | 30 + cl/DCF-CPP/src/CppSerializeAST.cpp | 892 ++ cl/DCF-CPP/src/LanguageFactory.cpp | 64 + cl/DCF-CPP/src/RepeatingLinesFilter.cpp | 67 + cl/DCF-CPP/src/StatementFilter.cpp | 47 + cl/DCF-CPP/src/dcm.cpp | 4491 ++++++ cl/DCF-CPP/src/main.cpp | 338 + cl/DuplicatedCodeFinder/inc/AbstractFilter.h | 1 - .../inc/Visitors/CSharpNamedVisitor.h | 8 +- .../inc/Visitors/CloneVisitorBase.h | 1 - cl/DuplicatedCodeFinder/inc/dcm.h | 53 +- .../src/AbstractFilter.cpp | 2 +- .../src/CloneVisitorBase.cpp | 76 +- cl/DuplicatedCodeFinder/src/dcm.cpp | 127 +- cl/ESLint2Graph/CMakeLists.txt | 1 + cl/ESLint2Graph/TSLint.rul | 7701 +++++++++++ cl/JAN2Lim/inc/CommentVisitor.h | 3 +- cl/JAN2Lim/src/HalsteadVisitor.cpp | 2 +- cl/JAN2Lim/src/JAN2LimVisitor.cpp | 2 +- cl/JSAN2Lim/src/HalsteadVisitor.cpp | 6 +- cl/JSAN2Lim/src/JSAN2LimVisitor.cpp | 19 +- cl/LIM2Metrics/MET.rul | 2831 +--- cl/LIM2Metrics/main.cpp | 3 +- cl/LIM2Patterns/CMakeLists.txt | 56 +- .../inc/Conditions/PythonCondition.h | 8 +- cl/LIM2Patterns/src/Helpers.cpp | 2 +- cl/LIM2Patterns/src/LIM2Patterns.cpp | 2 +- cl/MetricHunter/src/ThresholdReader.cpp | 2 +- cl/OpenStaticAnalyzerCPP/CMakeLists.txt | 25 + cl/OpenStaticAnalyzerCPP/inc/Properties.h | 140 + cl/OpenStaticAnalyzerCPP/inc/Task.h | 109 + cl/OpenStaticAnalyzerCPP/inc/messages.h | 44 + cl/OpenStaticAnalyzerCPP/rules_cpp.csv | 738 + cl/OpenStaticAnalyzerCPP/src/Task.cpp | 1230 ++ cl/OpenStaticAnalyzerCPP/src/main.cpp | 606 + .../inc/Properties.h | 8 +- .../rules_javascript.csv | 1 - cl/OpenStaticAnalyzerJavaScript/src/Task.cpp | 12 +- cl/OpenStaticAnalyzerJavaScript/src/main.cpp | 52 +- cl/PAN/inc/VisitorType.h | 1 - cl/PAN/src/main.cpp | 2 +- cl/ParamCheck/CMakeLists.txt | 12 + cl/ParamCheck/main.cpp | 67 + .../ParamCheck/messages.h | 7 + cl/Sonar2Graph/src/main.cpp | 2 +- cl/UserDefinedMetrics/src/UdmFunction.cpp | 8 +- csharp/DefaultValues.props | 2 +- .../RoslynVisitors/RoslynVisitor.Statement.cs | 2 +- inc/ReleaseVersion.h | 2 +- .../src/main/java/org/jan/TypeBuilder.java | 2 +- java/lib/openjdk | 2 +- javascript/cl/ESLintRunner/.gitignore | 2 + javascript/cl/ESLintRunner/CMakeLists.txt | 42 +- javascript/cl/ESLintRunner/ESLintRunner.js | 630 +- .../OpenStaticAnalyzerFormater.js | 75 - javascript/cl/ESLintRunner/eslint.json | 353 - javascript/cl/ESLintRunner/fix_esquery.js | 34 + javascript/cl/ESLintRunner/outputFormatter.js | 89 + javascript/cl/ESLintRunner/package-lock.json | 11473 ++++++++++++++++ javascript/cl/ESLintRunner/package.json | 37 +- .../cl/ESLintRunner/src/assets/constants.js | 23 + .../cl/ESLintRunner/src/assets/options.js | 223 +- .../src/assets/toolDescription.js | 7 +- javascript/cl/ESLintRunner/src/globals.js | 113 +- .../cl/ESLintRunner/typescript-eslint.json | 477 + javascript/cl/ESLintRunner/webpack.common.js | 48 + javascript/cl/ESLintRunner/webpack.dev.js | 8 + javascript/cl/ESLintRunner/webpack.prod.js | 10 + javascript/cl/JSAN/.gitignore | 2 + javascript/cl/JSAN/CMakeLists.txt | 34 +- javascript/cl/JSAN/package-lock.json | 2485 ++++ javascript/cl/JSAN/package.json | 36 +- .../cl/JSAN/src/assets/crossRefSolver.js | 246 - .../cl/JSAN/src/assets/htmlExtractor.js | 267 +- javascript/cl/JSAN/src/assets/options.js | 159 +- javascript/cl/JSAN/src/assets/scopeManager.js | 103 + .../cl/JSAN/src/assets/toolDescription.js | 17 +- javascript/cl/JSAN/src/assets/varUsages.js | 76 + javascript/cl/JSAN/src/ast/astTransformer.js | 604 +- javascript/cl/JSAN/src/ast/base/program.js | 31 +- javascript/cl/JSAN/src/ast/conversions.js | 51 +- .../src/ast/declaration/classDeclaration.js | 34 +- .../ast/declaration/exportAllDeclaration.js | 27 +- .../declaration/exportDefaultDeclaration.js | 21 +- .../ast/declaration/exportNamedDeclaration.js | 36 +- .../ast/declaration/functionDeclaration.js | 43 +- .../src/ast/declaration/importDeclaration.js | 29 +- .../ast/declaration/variableDeclaration.js | 24 +- .../src/ast/declaration/variableDeclarator.js | 28 +- .../src/ast/expression/arrayExpression.js | 22 +- .../ast/expression/arrowFunctionExpression.js | 37 +- .../ast/expression/assignmentExpression.js | 30 +- .../src/ast/expression/awaitExpression.js | 21 +- .../src/ast/expression/binaryExpression.js | 29 +- .../JSAN/src/ast/expression/callExpression.js | 29 +- .../src/ast/expression/chainExpression.js | 20 + .../src/ast/expression/classExpression.js | 36 +- .../ast/expression/conditionalExpression.js | 35 +- .../src/ast/expression/functionExpression.js | 36 +- .../cl/JSAN/src/ast/expression/identifier.js | 11 +- .../src/ast/expression/importExpression.js | 20 + .../cl/JSAN/src/ast/expression/literal.js | 21 +- .../src/ast/expression/logicalExpression.js | 30 +- .../src/ast/expression/memberExpression.js | 27 +- .../JSAN/src/ast/expression/metaProperty.js | 27 +- .../JSAN/src/ast/expression/newExpression.js | 29 +- .../src/ast/expression/objectExpression.js | 22 +- .../src/ast/expression/privateIdentifier.js | 22 + .../cl/JSAN/src/ast/expression/property.js | 29 +- .../JSAN/src/ast/expression/regExpLiteral.js | 11 +- .../src/ast/expression/sequenceExpression.js | 21 +- .../JSAN/src/ast/expression/spreadElement.js | 21 +- .../cl/JSAN/src/ast/expression/super.js | 11 +- .../expression/taggedTemplateExpression.js | 28 +- .../src/ast/expression/templateElement.js | 11 +- .../src/ast/expression/templateLiteral.js | 39 +- .../JSAN/src/ast/expression/thisExpression.js | 21 +- .../src/ast/expression/unaryExpression.js | 23 +- .../src/ast/expression/updateExpression.js | 22 +- .../src/ast/expression/yieldExpression.js | 21 +- .../cl/JSAN/src/ast/statement/arrayPattern.js | 22 +- .../src/ast/statement/assignmentPattern.js | 28 +- .../JSAN/src/ast/statement/blockStatement.js | 22 +- .../JSAN/src/ast/statement/breakStatement.js | 21 +- .../cl/JSAN/src/ast/statement/catchClause.js | 28 +- .../src/ast/statement/continueStatement.js | 21 +- .../src/ast/statement/debuggerStatement.js | 11 +- .../src/ast/statement/doWhileStatement.js | 28 +- .../JSAN/src/ast/statement/emptyStatement.js | 11 +- .../src/ast/statement/expressionStatement.js | 21 +- .../JSAN/src/ast/statement/forInStatement.js | 35 +- .../JSAN/src/ast/statement/forOfStatement.js | 39 +- .../cl/JSAN/src/ast/statement/forStatement.js | 43 +- .../cl/JSAN/src/ast/statement/ifStatement.js | 36 +- .../src/ast/statement/labeledStatement.js | 29 +- .../JSAN/src/ast/statement/objectPattern.js | 22 +- .../cl/JSAN/src/ast/statement/restElement.js | 21 +- .../JSAN/src/ast/statement/returnStatement.js | 21 +- .../cl/JSAN/src/ast/statement/switchCase.js | 31 +- .../JSAN/src/ast/statement/switchStatement.js | 32 +- .../JSAN/src/ast/statement/throwStatement.js | 21 +- .../cl/JSAN/src/ast/statement/tryStatement.js | 35 +- .../JSAN/src/ast/statement/whileStatement.js | 26 +- .../JSAN/src/ast/statement/withStatement.js | 27 +- javascript/cl/JSAN/src/ast/structure/class.js | 35 +- .../cl/JSAN/src/ast/structure/classBody.js | 22 +- .../JSAN/src/ast/structure/exportSpecifier.js | 27 +- .../ast/structure/importDefaultSpecifier.js | 21 +- .../ast/structure/importNamespaceSpecifier.js | 21 +- .../JSAN/src/ast/structure/importSpecifier.js | 27 +- .../src/ast/structure/methodDefinition.js | 29 +- .../src/ast/structure/propertyDefinition.js | 28 + javascript/cl/JSAN/src/globals.js | 123 +- javascript/cl/JSAN/{JSAN.js => src/index.js} | 137 +- javascript/cl/JSAN/src/util/tree.js | 24 + javascript/cl/JSAN/src/util/util.js | 31 + javascript/cl/JSAN/webpack.common.js | 31 + javascript/cl/JSAN/webpack.dev.js | 7 + javascript/cl/JSAN/webpack.prod.js | 10 + lib/archivecpp/CMakeLists.txt | 12 + lib/archivecpp/inc/ArchiveHandler.h | 91 + lib/archivecpp/inc/messages.h | 36 + lib/archivecpp/src/ArchiveHandler.cpp | 279 + lib/clangsupport/ASTFilter.cpp | 218 + lib/clangsupport/ASTFilter.h | 63 + lib/clangsupport/ASTIDMapGenerator.cpp | 67 + .../ASTIDMapGenerator.h} | 34 +- lib/clangsupport/ASTLoader.cpp | 61 + lib/clangsupport/ASTLoader.h | 46 + lib/clangsupport/ASTSupport.cpp | 47 + lib/clangsupport/ASTSupport.h | 34 + lib/clangsupport/CANCommon.h | 123 + lib/clangsupport/CMakeLists.txt | 19 + lib/clangsupport/messages.h | 32 + lib/common/inc/Stat.h | 8 + lib/controller/src/ProfileHandler.cpp | 2 - lib/csharp/inc/Factory.h | 4 +- lib/genealogy/inc/Factory.h | 4 +- lib/graphsupport/CMakeLists.txt | 4 +- lib/graphsupport/inc/SarifExporter.h | 5 +- lib/graphsupport/inc/SarifWriter.h | 83 - lib/graphsupport/src/CsvExporter.cpp | 2 + lib/graphsupport/src/SarifExporter.cpp | 575 +- lib/graphsupport/src/SarifWriter.cpp | 214 - lib/io/inc/ZippedIO.h | 12 +- lib/io/src/BinaryIO.cpp | 2 +- lib/java/inc/Factory.h | 4 +- lib/javascript/CMakeLists.txt | 14 +- lib/javascript/addon/Factory.cc | 168 +- lib/javascript/addon/Factory.h | 22 +- lib/javascript/addon/addon.cc | 22 +- lib/javascript/addon/binding.gyp | 4 +- .../addon/inc/BigIntLiteralWrapper.h | 52 + .../addon/inc/CallExpressionWrapper.h | 1 + .../addon/inc/ChainElementWrapper.h | 51 + .../addon/inc/ChainExpressionWrapper.h | 51 + .../addon/inc/ExportAllDeclarationWrapper.h | 1 + .../addon/inc/ForOfStatementWrapper.h | 2 +- .../addon/inc/ImportExpressionWrapper.h | 51 + .../addon/inc/MemberExpressionWrapper.h | 1 + .../addon/inc/PrivateIdentifierWrapper.h | 51 + ...yWrapper.h => PropertyDefinitionWrapper.h} | 20 +- .../addon/src/AssignmentExpressionWrapper.cc | 9 + .../addon/src/BigIntLiteralWrapper.cc | 303 + .../addon/src/BinaryExpressionWrapper.cc | 4 +- .../addon/src/CallExpressionWrapper.cc | 33 + .../addon/src/ChainElementWrapper.cc | 254 + .../addon/src/ChainExpressionWrapper.cc | 256 + lib/javascript/addon/src/ClassBodyWrapper.cc | 4 +- .../addon/src/ExportAllDeclarationWrapper.cc | 35 + .../addon/src/ForOfStatementWrapper.cc | 6 +- .../addon/src/ImportExpressionWrapper.cc | 256 + .../addon/src/LogicalExpressionWrapper.cc | 3 + .../addon/src/MemberExpressionWrapper.cc | 37 +- .../addon/src/MethodDefinitionWrapper.cc | 4 +- .../addon/src/PrivateIdentifierWrapper.cc | 262 + ...rapper.cc => PropertyDefinitionWrapper.cc} | 158 +- lib/javascript/inc/Common.h | 47 +- lib/javascript/inc/Constant.h | 4 +- lib/javascript/inc/Factory.h | 45 +- lib/javascript/inc/Forwards.h | 7 +- lib/javascript/inc/ReverseEdges.h | 9 +- lib/javascript/inc/Types.h | 16 +- .../inc/algorithms/AlgorithmPreorder.h | 80 +- .../inc/declaration/ExportAllDeclaration.h | 27 + lib/javascript/inc/expression/BigIntLiteral.h | 203 + .../inc/expression/BinaryExpression.h | 6 +- .../inc/expression/CallExpression.h | 2 +- lib/javascript/inc/expression/ChainElement.h | 189 + .../inc/expression/ChainExpression.h | 201 + .../inc/expression/ImportExpression.h | 201 + .../inc/expression/MemberExpression.h | 8 +- ...signmentProperty.h => PrivateIdentifier.h} | 20 +- lib/javascript/inc/javascript.h | 35 +- lib/javascript/inc/statement/ForOfStatement.h | 18 +- lib/javascript/inc/structure/ClassBody.h | 12 +- .../inc/structure/MethodDefinition.h | 6 +- .../inc/structure/PropertyDefinition.h | 273 + lib/javascript/inc/visitors/Visitor.h | 162 +- .../inc/visitors/VisitorAbstractNodes.h | 86 +- lib/javascript/inc/visitors/VisitorAsgStat.h | 87 +- lib/javascript/inc/visitors/VisitorFilter.h | 34 +- lib/javascript/inc/visitors/VisitorGraphml.h | 171 +- .../inc/visitors/VisitorJAVASCRIPTML.h | 200 +- .../inc/visitors/VisitorReverseEdges.h | 43 +- .../inc/visitors/VisitorSimpleEdge.h | 86 +- lib/javascript/src/Common.cpp | 101 +- lib/javascript/src/Factory.cpp | 53 +- lib/javascript/src/ListIterator.cpp | 1 - lib/javascript/src/ReverseEdges.cpp | 183 +- .../src/algorithms/AlgorithmPreorder.cpp | 403 +- .../src/declaration/ExportAllDeclaration.cpp | 71 +- .../src/expression/AssignmentProperty.cpp | 123 - .../src/expression/BigIntLiteral.cpp | 194 + .../src/expression/BinaryExpression.cpp | 32 +- .../src/expression/CallExpression.cpp | 17 +- .../src/expression/ChainElement.cpp | 147 + .../src/expression/ChainExpression.cpp | 215 + .../src/expression/ImportExpression.cpp | 215 + .../src/expression/MemberExpression.cpp | 47 +- .../src/expression/ObjectExpression.cpp | 2 +- .../src/expression/PrivateIdentifier.cpp | 157 + .../src/statement/ForOfStatement.cpp | 16 +- .../src/statement/ObjectPattern.cpp | 2 +- lib/javascript/src/structure/ClassBody.cpp | 24 +- .../src/structure/MethodDefinition.cpp | 32 +- .../src/structure/PropertyDefinition.cpp | 305 + lib/javascript/src/visitors/Visitor.cpp | 64 +- .../src/visitors/VisitorAbstractNodes.cpp | 78 +- .../src/visitors/VisitorAsgStat.cpp | 104 +- lib/javascript/src/visitors/VisitorFilter.cpp | 24 +- .../src/visitors/VisitorGraphml.cpp | 557 +- .../src/visitors/VisitorJAVASCRIPTML.cpp | 226 +- .../src/visitors/VisitorReverseEdges.cpp | 28 +- .../src/visitors/VisitorSimpleEdge.cpp | 96 +- lib/jsoncpp/inc/writer.h | 1 + lib/jsoncpp/src/json_writer.cpp | 17 + lib/lim/inc/Factory.h | 4 +- lib/lim/src/ClassDiagram.cpp | 7 +- lib/limmetrics/CMakeLists.txt | 9 - lib/limmetrics/inc/LimMetrics.h | 6 +- lib/limmetrics/inc/RulParser.h | 33 +- lib/limmetrics/inc/metrics/Aggregates.h | 36 - lib/limmetrics/inc/metrics/CBO.h | 10 +- lib/limmetrics/inc/metrics/Documentation.h | 24 - lib/limmetrics/inc/metrics/Halstead.h | 100 - lib/limmetrics/inc/metrics/NA.h | 86 - lib/limmetrics/inc/metrics/NL.h | 58 - lib/limmetrics/src/LimMetrics.cpp | 29 +- lib/limmetrics/src/MetricHandler.cpp | 2 +- lib/limmetrics/src/RulParser.cpp | 177 +- lib/limmetrics/src/metrics/Aggregates.cpp | 44 - lib/limmetrics/src/metrics/CBO.cpp | 56 +- lib/limmetrics/src/metrics/Documentation.cpp | 68 +- lib/limmetrics/src/metrics/Halstead.cpp | 192 - lib/limmetrics/src/metrics/NA.cpp | 203 - lib/limmetrics/src/metrics/NII.cpp | 140 - lib/limmetrics/src/metrics/NL.cpp | 95 - lib/python/inc/Factory.h | 4 +- .../src/abstractwrapper/AbstractArchive.cpp | 16 +- .../src/abstractwrapper/AbstractCompiler.cpp | 8 +- 414 files changed, 84771 insertions(+), 8942 deletions(-) create mode 160000 3rdparty/clang create mode 160000 3rdparty/cppcheck create mode 160000 3rdparty/miniz create mode 100644 CMake/AddExecutablePermission.cmake create mode 100644 CMake/Clang.cmake create mode 100644 OpenStaticAnalyzer/cpp/CMakeLists.txt create mode 100644 OpenStaticAnalyzer/cpp/demo/analyze.bat create mode 100755 OpenStaticAnalyzer/cpp/demo/analyze.sh create mode 100644 OpenStaticAnalyzer/cpp/demo/build-win-x64.bat create mode 100755 OpenStaticAnalyzer/cpp/demo/build.sh create mode 100644 OpenStaticAnalyzer/cpp/demo/log4cplus-1.1.0.zip create mode 100644 OpenStaticAnalyzer/cpp/demo/softfilter-linux create mode 100644 OpenStaticAnalyzer/cpp/demo/softfilter-windows create mode 100644 OpenStaticAnalyzer/cpp/doc/usersguide/CMakeLists.txt create mode 100644 OpenStaticAnalyzer/cpp/doc/usersguide/img/structure.png create mode 100644 OpenStaticAnalyzer/cpp/doc/usersguide/md/ClangTidyRef.md create mode 100644 OpenStaticAnalyzer/cpp/doc/usersguide/md/CodeDuplicationMetricsRef.md create mode 100644 OpenStaticAnalyzer/cpp/doc/usersguide/md/CppcheckRef.md create mode 100644 OpenStaticAnalyzer/cpp/doc/usersguide/md/Footnotes.md create mode 100644 OpenStaticAnalyzer/cpp/doc/usersguide/md/Main.md create mode 100644 OpenStaticAnalyzer/cpp/doc/usersguide/md/SourceCodeMetricsRef.md create mode 100644 OpenStaticAnalyzer/cpp/doc/usersguide/md/WrappingTips.md create mode 100644 cl/CAN/CMakeLists.txt create mode 100644 cl/CAN/src/main.cpp create mode 100644 cl/CAN2Lim/CMakeLists.txt create mode 100644 cl/CAN2Lim/inc/ASTConversionInfo.h create mode 100644 cl/CAN2Lim/inc/ASTVisitor.h create mode 100644 cl/CAN2Lim/inc/CommentProcessor.h create mode 100644 cl/CAN2Lim/inc/Linker.h create mode 100644 cl/CAN2Lim/inc/MergeUID.h create mode 100644 cl/CAN2Lim/inc/clangHelpers.h create mode 100644 cl/CAN2Lim/inc/messages.h create mode 100644 cl/CAN2Lim/src/ASTConversionInfo.cpp create mode 100644 cl/CAN2Lim/src/ASTVisitor.cpp create mode 100644 cl/CAN2Lim/src/CommentProcessor.cpp create mode 100644 cl/CAN2Lim/src/Linker.cpp create mode 100644 cl/CAN2Lim/src/MergeUID.cpp create mode 100644 cl/CAN2Lim/src/clangHelpers.cpp create mode 100644 cl/CAN2Lim/src/main.cpp create mode 100644 cl/CANConfig/CMakeLists.txt create mode 100644 cl/CANConfig/main.cpp create mode 100644 cl/CANConfig/messages.h create mode 100644 cl/CANLib/CMakeLists.txt create mode 100644 cl/CANLib/inc/messages.h create mode 100644 cl/CANLib/src/main.cpp create mode 100644 cl/CANLink/CMakeLists.txt create mode 100644 cl/CANLink/inc/messages.h create mode 100644 cl/CANLink/src/main.cpp create mode 100644 cl/ClangTidy2Graph/CMakeLists.txt create mode 100644 cl/ClangTidy2Graph/ClangTidy.rul create mode 100644 cl/ClangTidy2Graph/inc/ResultConverter.h create mode 100644 cl/ClangTidy2Graph/inc/defines.h create mode 100644 cl/ClangTidy2Graph/inc/messages.h create mode 100644 cl/ClangTidy2Graph/rules.csv create mode 100644 cl/ClangTidy2Graph/src/ResultConverter.cpp create mode 100644 cl/ClangTidy2Graph/src/main.cpp create mode 100644 cl/Cppcheck2Graph/CMakeLists.txt create mode 100644 cl/Cppcheck2Graph/Cppcheck.rul create mode 100644 cl/Cppcheck2Graph/errorgroups.xml create mode 100644 cl/Cppcheck2Graph/errorlist.xml create mode 100644 cl/Cppcheck2Graph/inc/ResultConverter.h create mode 100644 cl/Cppcheck2Graph/inc/RuleConverter.h create mode 100644 cl/Cppcheck2Graph/inc/XMLParser.h create mode 100644 cl/Cppcheck2Graph/inc/defines.h create mode 100644 cl/Cppcheck2Graph/inc/messages.h create mode 100644 cl/Cppcheck2Graph/listerrors.xslt create mode 100644 cl/Cppcheck2Graph/options.csv create mode 100644 cl/Cppcheck2Graph/src/ResultConverter.cpp create mode 100644 cl/Cppcheck2Graph/src/RuleConverter.cpp create mode 100644 cl/Cppcheck2Graph/src/XMLParser.cpp create mode 100644 cl/Cppcheck2Graph/src/main.cpp create mode 100644 cl/DCF-CPP/CMakeLists.txt create mode 100644 cl/DCF-CPP/inc/AbstractFilter.h rename javascript/cl/JSAN/src/ast/expression/assignmentProperty.js => cl/DCF-CPP/inc/Aligner.h (84%) create mode 100644 cl/DCF-CPP/inc/CPPNamedVisitor.h create mode 100644 cl/DCF-CPP/inc/CloneLengthFilter.h create mode 100644 cl/DCF-CPP/inc/CloneOccuranceFilter.h create mode 100644 cl/DCF-CPP/inc/ClonePositioned.h create mode 100644 cl/DCF-CPP/inc/Config.h create mode 100644 cl/DCF-CPP/inc/CppSerializeAST.h create mode 100644 cl/DCF-CPP/inc/DistanceVisitor.h create mode 100644 cl/DCF-CPP/inc/Interval.h create mode 100644 cl/DCF-CPP/inc/LanguageFactory.h create mode 100644 cl/DCF-CPP/inc/RepeatingLinesFilter.h create mode 100644 cl/DCF-CPP/inc/StatementFilter.h create mode 100644 cl/DCF-CPP/inc/Types.h create mode 100644 cl/DCF-CPP/inc/dcm.h create mode 100644 cl/DCF-CPP/inc/messages.h create mode 100644 cl/DCF-CPP/src/AbstractFilter.cpp create mode 100644 cl/DCF-CPP/src/CloneLengthFilter.cpp create mode 100644 cl/DCF-CPP/src/ClonePositioned.cpp create mode 100644 cl/DCF-CPP/src/CppSerializeAST.cpp create mode 100644 cl/DCF-CPP/src/LanguageFactory.cpp create mode 100644 cl/DCF-CPP/src/RepeatingLinesFilter.cpp create mode 100644 cl/DCF-CPP/src/StatementFilter.cpp create mode 100644 cl/DCF-CPP/src/dcm.cpp create mode 100644 cl/DCF-CPP/src/main.cpp create mode 100644 cl/ESLint2Graph/TSLint.rul create mode 100644 cl/OpenStaticAnalyzerCPP/CMakeLists.txt create mode 100644 cl/OpenStaticAnalyzerCPP/inc/Properties.h create mode 100644 cl/OpenStaticAnalyzerCPP/inc/Task.h create mode 100644 cl/OpenStaticAnalyzerCPP/inc/messages.h create mode 100644 cl/OpenStaticAnalyzerCPP/rules_cpp.csv create mode 100644 cl/OpenStaticAnalyzerCPP/src/Task.cpp create mode 100644 cl/OpenStaticAnalyzerCPP/src/main.cpp create mode 100644 cl/ParamCheck/CMakeLists.txt create mode 100644 cl/ParamCheck/main.cpp rename javascript/cl/JSAN/src/ast/declaration/moduleDeclaration.js => cl/ParamCheck/messages.h (86%) create mode 100644 javascript/cl/ESLintRunner/.gitignore delete mode 100644 javascript/cl/ESLintRunner/OpenStaticAnalyzerFormater.js delete mode 100644 javascript/cl/ESLintRunner/eslint.json create mode 100644 javascript/cl/ESLintRunner/fix_esquery.js create mode 100644 javascript/cl/ESLintRunner/outputFormatter.js create mode 100644 javascript/cl/ESLintRunner/package-lock.json create mode 100644 javascript/cl/ESLintRunner/src/assets/constants.js create mode 100644 javascript/cl/ESLintRunner/typescript-eslint.json create mode 100644 javascript/cl/ESLintRunner/webpack.common.js create mode 100644 javascript/cl/ESLintRunner/webpack.dev.js create mode 100644 javascript/cl/ESLintRunner/webpack.prod.js create mode 100644 javascript/cl/JSAN/package-lock.json delete mode 100644 javascript/cl/JSAN/src/assets/crossRefSolver.js create mode 100644 javascript/cl/JSAN/src/assets/scopeManager.js create mode 100644 javascript/cl/JSAN/src/assets/varUsages.js create mode 100644 javascript/cl/JSAN/src/ast/expression/chainExpression.js create mode 100644 javascript/cl/JSAN/src/ast/expression/importExpression.js create mode 100644 javascript/cl/JSAN/src/ast/expression/privateIdentifier.js create mode 100644 javascript/cl/JSAN/src/ast/structure/propertyDefinition.js rename javascript/cl/JSAN/{JSAN.js => src/index.js} (74%) create mode 100644 javascript/cl/JSAN/src/util/tree.js create mode 100644 javascript/cl/JSAN/src/util/util.js create mode 100644 javascript/cl/JSAN/webpack.common.js create mode 100644 javascript/cl/JSAN/webpack.dev.js create mode 100644 javascript/cl/JSAN/webpack.prod.js create mode 100644 lib/archivecpp/CMakeLists.txt create mode 100644 lib/archivecpp/inc/ArchiveHandler.h create mode 100644 lib/archivecpp/inc/messages.h create mode 100644 lib/archivecpp/src/ArchiveHandler.cpp create mode 100644 lib/clangsupport/ASTFilter.cpp create mode 100644 lib/clangsupport/ASTFilter.h create mode 100644 lib/clangsupport/ASTIDMapGenerator.cpp rename lib/{limmetrics/inc/metrics/NII.h => clangsupport/ASTIDMapGenerator.h} (59%) create mode 100644 lib/clangsupport/ASTLoader.cpp create mode 100644 lib/clangsupport/ASTLoader.h create mode 100644 lib/clangsupport/ASTSupport.cpp create mode 100644 lib/clangsupport/ASTSupport.h create mode 100644 lib/clangsupport/CANCommon.h create mode 100644 lib/clangsupport/CMakeLists.txt create mode 100644 lib/clangsupport/messages.h delete mode 100644 lib/graphsupport/inc/SarifWriter.h delete mode 100644 lib/graphsupport/src/SarifWriter.cpp create mode 100644 lib/javascript/addon/inc/BigIntLiteralWrapper.h create mode 100644 lib/javascript/addon/inc/ChainElementWrapper.h create mode 100644 lib/javascript/addon/inc/ChainExpressionWrapper.h create mode 100644 lib/javascript/addon/inc/ImportExpressionWrapper.h create mode 100644 lib/javascript/addon/inc/PrivateIdentifierWrapper.h rename lib/javascript/addon/inc/{AssignmentPropertyWrapper.h => PropertyDefinitionWrapper.h} (74%) create mode 100644 lib/javascript/addon/src/BigIntLiteralWrapper.cc create mode 100644 lib/javascript/addon/src/ChainElementWrapper.cc create mode 100644 lib/javascript/addon/src/ChainExpressionWrapper.cc create mode 100644 lib/javascript/addon/src/ImportExpressionWrapper.cc create mode 100644 lib/javascript/addon/src/PrivateIdentifierWrapper.cc rename lib/javascript/addon/src/{AssignmentPropertyWrapper.cc => PropertyDefinitionWrapper.cc} (64%) create mode 100644 lib/javascript/inc/expression/BigIntLiteral.h create mode 100644 lib/javascript/inc/expression/ChainElement.h create mode 100644 lib/javascript/inc/expression/ChainExpression.h create mode 100644 lib/javascript/inc/expression/ImportExpression.h rename lib/javascript/inc/expression/{AssignmentProperty.h => PrivateIdentifier.h} (88%) create mode 100644 lib/javascript/inc/structure/PropertyDefinition.h delete mode 100644 lib/javascript/src/expression/AssignmentProperty.cpp create mode 100644 lib/javascript/src/expression/BigIntLiteral.cpp create mode 100644 lib/javascript/src/expression/ChainElement.cpp create mode 100644 lib/javascript/src/expression/ChainExpression.cpp create mode 100644 lib/javascript/src/expression/ImportExpression.cpp create mode 100644 lib/javascript/src/expression/PrivateIdentifier.cpp create mode 100644 lib/javascript/src/structure/PropertyDefinition.cpp delete mode 100644 lib/limmetrics/inc/metrics/Halstead.h delete mode 100644 lib/limmetrics/inc/metrics/NA.h delete mode 100644 lib/limmetrics/inc/metrics/NL.h delete mode 100644 lib/limmetrics/src/metrics/Halstead.cpp delete mode 100644 lib/limmetrics/src/metrics/NA.cpp delete mode 100644 lib/limmetrics/src/metrics/NII.cpp delete mode 100644 lib/limmetrics/src/metrics/NL.cpp diff --git a/.gitmodules b/.gitmodules index a664d4b..65d5279 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,10 +9,12 @@ url = https://github.com/sed-inf-u-szeged/pmd.git [submodule "3rdparty/python2"] path = 3rdparty/python2 - url = ../cpython + url = ../cpython.git + ignore = dirty [submodule "3rdparty/python3"] path = 3rdparty/python3 - url = ../cpython + url = ../cpython.git + ignore = dirty [submodule "cl/LIM2Patterns/pybind11"] path = cl/LIM2Patterns/pybind11 url = https://github.com/pybind/pybind11 @@ -20,3 +22,12 @@ path = java/lib/openjdk url = ../openjdk ignore = dirty +[submodule "3rdparty/clang"] + path = 3rdparty/clang + url = ../llvm-project +[submodule "3rdparty/cppheck"] + path = 3rdparty/cppcheck + url = https://github.com/danmar/cppcheck.git +[submodule "3rdparty/miniz"] + path = 3rdparty/miniz + url = https://github.com/richgel999/miniz.git diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt index 1213b35..ed49667 100644 --- a/3rdparty/CMakeLists.txt +++ b/3rdparty/CMakeLists.txt @@ -1,4 +1,5 @@ include(ExternalProject) +set(BUILD_SHARED_LIBS OFF) # All the external static library names should follow this naming convention: # Linux: @@ -11,7 +12,7 @@ file (MAKE_DIRECTORY ${COLUMBUS_3RDPARTY_INSTALL_DIR}/lib) file (MAKE_DIRECTORY ${COLUMBUS_3RDPARTY_INSTALL_DIR}/include) # Disable warnings during building 3rdparty code -if (CMAKE_SYSTEM_NAME STREQUAL Linux) +if (CMAKE_CXX_COMPILER_ID MATCHES GNU|Clang) add_compile_options("-w") endif() @@ -22,7 +23,7 @@ ExternalProject_Add(zlib PATCH_COMMAND git clean -x -d -f COMMAND git reset --hard COMMAND git apply --ignore-whitespace ${CMAKE_CURRENT_SOURCE_DIR}/CMake/zlib.patch - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${COLUMBUS_3RDPARTY_INSTALL_DIR} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${COLUMBUS_3RDPARTY_INSTALL_DIR} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} LOG_CONFIGURE 1 LOG_BUILD 1 LOG_INSTALL 1 @@ -39,26 +40,26 @@ endif() ########################### boost ######################## -if (CMAKE_SYSTEM_NAME STREQUAL Windows) - if (COLUMBUS_64BIT) - set (BOOST_ADDRESS_MODEL address-model=64) - endif () - set (BOOST_MSVC_TOOLSET toolset=msvc-14.1) -endif () - -if (CMAKE_SYSTEM_NAME STREQUAL Linux) +if (CMAKE_CXX_COMPILER_ID STREQUAL MSVC) + set (BOOST_TOOLSET toolset=msvc-14.1) +elseif (CMAKE_CXX_COMPILER_ID MATCHES GNU|Clang) set (BOOST_EXTRA_CXX_COMPILER_FLAGS cxxflags=-fPIC) set (BOOST_EXTRA_C_COMPILER_FLAGS cflags=-fPIC) -endif () + if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set (BOOST_TOOLSET toolset=gcc-${CMAKE_CXX_COMPILER_VERSION}) + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set (BOOST_TOOLSET toolset=clang-${CMAKE_CXX_COMPILER_VERSION}) + endif() +endif () ExternalProject_Add(boost DEPENDS zlib SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/boost BUILD_IN_SOURCE 1 CONFIGURE_COMMAND ${COMMAND_PREFIX}bootstrap${SCRIPT_EXT} - BUILD_COMMAND ${COMMAND_PREFIX}b2 ${BOOST_EXTRA_CXX_COMPILER_FLAGS} ${BOOST_EXTRA_C_COMPILER_FLAGS} ${BOOST_MSVC_TOOLSET} --reconfigure --build-dir=${CMAKE_CURRENT_BINARY_DIR}/boost-prefix --prefix=${COLUMBUS_3RDPARTY_INSTALL_DIR} -j8 --with-filesystem --with-system --with-date_time --with-iostreams --with-graph --with-regex --with-thread --with-math --layout=system variant=$<$:debug>$<$:release> runtime-link=static architecture=x86 threading=multi ${BOOST_ADDRESS_MODEL} link=static -sZLIB_INCLUDE=${COLUMBUS_3RDPARTY_INSTALL_DIR}/include -sZLIB_LIBPATH=${COLUMBUS_3RDPARTY_INSTALL_DIR}/lib -sZLIB_BINARY=z -sNO_ZLIB=0 -sNO_BZIP2=1 headers - COMMAND ${COMMAND_PREFIX}b2 ${BOOST_EXTRA_CXX_COMPILER_FLAGS} ${BOOST_EXTRA_C_COMPILER_FLAGS} ${BOOST_MSVC_TOOLSET} --reconfigure --build-dir=${CMAKE_CURRENT_BINARY_DIR}/boost-prefix --prefix=${COLUMBUS_3RDPARTY_INSTALL_DIR} -j8 --with-filesystem --with-system --with-date_time --with-iostreams --with-graph --with-regex --with-thread --with-math --layout=system variant=$<$:debug>$<$:release> runtime-link=static architecture=x86 threading=multi ${BOOST_ADDRESS_MODEL} link=static -sZLIB_INCLUDE=${COLUMBUS_3RDPARTY_INSTALL_DIR}/include -sZLIB_LIBPATH=${COLUMBUS_3RDPARTY_INSTALL_DIR}/lib -sZLIB_BINARY=z -sNO_ZLIB=0 -sNO_BZIP2=1 install + BUILD_COMMAND ${COMMAND_PREFIX}b2 ${BOOST_EXTRA_CXX_COMPILER_FLAGS} ${BOOST_EXTRA_C_COMPILER_FLAGS} ${BOOST_TOOLSET} --reconfigure --build-dir=${CMAKE_CURRENT_BINARY_DIR}/boost-prefix --prefix=${COLUMBUS_3RDPARTY_INSTALL_DIR} -j8 --with-filesystem --with-system --with-date_time --with-iostreams --with-graph --with-regex --with-thread --with-math --layout=system variant=$<$:debug>$<$:release> runtime-link=static architecture=x86 threading=multi address-model=64 link=static -sZLIB_INCLUDE=${COLUMBUS_3RDPARTY_INSTALL_DIR}/include -sZLIB_LIBPATH=${COLUMBUS_3RDPARTY_INSTALL_DIR}/lib -sZLIB_BINARY=z -sNO_ZLIB=0 -sNO_BZIP2=1 headers + COMMAND ${COMMAND_PREFIX}b2 ${BOOST_EXTRA_CXX_COMPILER_FLAGS} ${BOOST_EXTRA_C_COMPILER_FLAGS} ${BOOST_TOOLSET} --reconfigure --build-dir=${CMAKE_CURRENT_BINARY_DIR}/boost-prefix --prefix=${COLUMBUS_3RDPARTY_INSTALL_DIR} -j8 --with-filesystem --with-system --with-date_time --with-iostreams --with-graph --with-regex --with-thread --with-math --layout=system variant=$<$:debug>$<$:release> runtime-link=static architecture=x86 threading=multi address-model=64 link=static -sZLIB_INCLUDE=${COLUMBUS_3RDPARTY_INSTALL_DIR}/include -sZLIB_LIBPATH=${COLUMBUS_3RDPARTY_INSTALL_DIR}/lib -sZLIB_BINARY=z -sNO_ZLIB=0 -sNO_BZIP2=1 install INSTALL_COMMAND ${CMAKE_COMMAND} -E echo "No sepearate installation step is needed." LOG_CONFIGURE 1 LOG_BUILD 1 @@ -116,12 +117,6 @@ if (CMAKE_SYSTEM_NAME STREQUAL Linux) elseif (CMAKE_SYSTEM_NAME STREQUAL Windows) - if (COLUMBUS_64BIT) - set (XERCESC_BUILD_OUTPUT_DIR Win64) - else() - set (XERCESC_BUILD_OUTPUT_DIR Win32) - endif () - ExternalProject_Add( xerces-c URL https://archive.apache.org/dist/xerces/c/3/sources/xerces-c-3.1.4.zip URL_HASH MD5=6fcd8ec268f6bfe11d8ce2cd7d25a185 @@ -130,7 +125,7 @@ elseif (CMAKE_SYSTEM_NAME STREQUAL Windows) BUILD_COMMAND msbuild projects/Win32/VC14/xerces-all/xerces-all.sln /m /t:XercesLib "/p:Configuration=Static $" /p:Platform=${VS_PLATFORM} /p:PlatformToolset=${CMAKE_VS_PLATFORM_TOOLSET} INSTALL_COMMAND ${CMAKE_COMMAND} "-DCOPY_SOURCE=${CMAKE_CURRENT_BINARY_DIR}/xerces-c-prefix/src/xerces-c/src/xercesc/" "-DCOPY_TARGET=${COLUMBUS_3RDPARTY_INSTALL_DIR}/include/xercesc" -DCOPY_PATTERN=*.hpp -P ${CMAKE_CURRENT_SOURCE_DIR}/CMake/SearchAndCopyFiles.cmake COMMAND ${CMAKE_COMMAND} "-DCOPY_SOURCE=${CMAKE_CURRENT_BINARY_DIR}/xerces-c-prefix/src/xerces-c/src/xercesc/" "-DCOPY_TARGET=${COLUMBUS_3RDPARTY_INSTALL_DIR}/include/xercesc" -DCOPY_PATTERN=*.c -P ${CMAKE_CURRENT_SOURCE_DIR}/CMake/SearchAndCopyFiles.cmake - COMMAND ${CMAKE_COMMAND} -E copy "Build/${XERCESC_BUILD_OUTPUT_DIR}/VC14/Static $/xerces-c_static_3$<$:d>.lib" ${COLUMBUS_3RDPARTY_INSTALL_DIR}/lib/xerces-c.lib + COMMAND ${CMAKE_COMMAND} -E copy "Build/Win64/VC14/Static $/xerces-c_static_3$<$:d>.lib" ${COLUMBUS_3RDPARTY_INSTALL_DIR}/lib/xerces-c.lib LOG_DOWNLOAD 1 LOG_CONFIGURE 1 LOG_BUILD 1 @@ -143,22 +138,20 @@ endif () set (PMD_PACKAGE_VERSION pmd-bin-6.32.0) set (PMD_DIST_PACKAGE ${CMAKE_CURRENT_SOURCE_DIR}/PMD/pmd-dist/target/${PMD_PACKAGE_VERSION}.zip) set (PMD_PACKAGE ${COLUMBUS_3RDPARTY_INSTALL_DIR}/PMD.zip) -if (CMAKE_SYSTEM_NAME STREQUAL Windows AND NOT COLUMBUS_64BIT) - set (PMD_MAVEN_OPTS ${CMAKE_COMMAND} -E env MAVEN_OPTS=-Xss16m) -endif () if (CMAKE_SYSTEM_NAME STREQUAL Windows) set (MVNW_POSTFIX .cmd) endif () add_custom_command ( OUTPUT ${PMD_PACKAGE} - COMMAND ${PMD_MAVEN_OPTS} ${COMMAND_PREFIX}mvnw${MVNW_POSTFIX} package -DskipTests -Dmaven.test.skip=true -Dmaven.javadoc.skip=true -Dmaven.source.skip=true -pl pmd-dist,pmd-core,pmd-java > ${CMAKE_CURRENT_BINARY_DIR}/PMD-build.log 2>&1 + COMMAND ${COMMAND_PREFIX}mvnw${MVNW_POSTFIX} package -DskipTests -Dmaven.test.skip=true -Dmaven.javadoc.skip=true -Dmaven.source.skip=true -pl pmd-dist,pmd-core,pmd-java > ${CMAKE_CURRENT_BINARY_DIR}/PMD-build.log 2>&1 COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_CURRENT_SOURCE_DIR}/PMD/pmd-dist/target/ ${CMAKE_COMMAND} -E remove_directory PMD COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_CURRENT_SOURCE_DIR}/PMD/pmd-dist/target/ ${CMAKE_COMMAND} -E tar xf ${PMD_DIST_PACKAGE} COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_CURRENT_SOURCE_DIR}/PMD/pmd-dist/target/ ${CMAKE_COMMAND} -E rename ${PMD_PACKAGE_VERSION} PMD COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_CURRENT_SOURCE_DIR}/PMD/pmd-dist/target/ ${CMAKE_COMMAND} -E tar cf ${PMD_DIST_PACKAGE} --format=zip PMD COMMAND ${CMAKE_COMMAND} -E copy ${PMD_DIST_PACKAGE} ${PMD_PACKAGE} COMMENT "Building PMD" + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/PMD WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/PMD ) @@ -175,7 +168,7 @@ set_target_properties (PMD PROPERTIES FOLDER "ExternalProjectTargets/pmd") ExternalProject_Add( spotbugs URL https://repo.maven.apache.org/maven2/com/github/spotbugs/spotbugs/4.2.2/spotbugs-4.2.2.tgz CONFIGURE_COMMAND "" - BUILD_COMMAND "" + BUILD_COMMAND ${CMAKE_COMMAND} -P ${CMAKE_MODULE_PATH}/AddExecutablePermission.cmake ${CMAKE_CURRENT_BINARY_DIR}/spotbugs-prefix/src/spotbugs/bin/spotbugs INSTALL_COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_CURRENT_BINARY_DIR}/spotbugs-prefix/src ${CMAKE_COMMAND} -E tar cf ${COLUMBUS_3RDPARTY_INSTALL_DIR}/spotbugs.zip --format=zip spotbugs LOG_DOWNLOAD 1 LOG_INSTALL 1 @@ -196,9 +189,6 @@ if (CMAKE_SYSTEM_NAME STREQUAL Linux) LOG_INSTALL 1 ) elseif (CMAKE_SYSTEM_NAME STREQUAL Windows) - if (COLUMBUS_64BIT) - set (PYTHON_BUILD_OUTPUT_DIR amd64) - endif () ExternalProject_Add( python2.7 DEPENDS zlib @@ -208,7 +198,7 @@ elseif (CMAKE_SYSTEM_NAME STREQUAL Windows) BUILD_COMMAND msbuild PCbuild/pythoncore.vcxproj /m /t:Build /p:Configuration=$ /p:Platform=${VS_PLATFORM} /p:PlatformToolset=${CMAKE_VS_PLATFORM_TOOLSET} INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory Include ${COLUMBUS_3RDPARTY_INSTALL_DIR}/include/python2.7 COMMAND ${CMAKE_COMMAND} -E copy "PC/pyconfig.h" ${COLUMBUS_3RDPARTY_INSTALL_DIR}/include/python2.7/pyconfig.h - COMMAND ${CMAKE_COMMAND} -E copy "PCbuild/${PYTHON_BUILD_OUTPUT_DIR}/python27$<$:_d>.lib" ${COLUMBUS_3RDPARTY_INSTALL_DIR}/lib/python2.7.lib + COMMAND ${CMAKE_COMMAND} -E copy "PCbuild/amd64/python27$<$:_d>.lib" ${COLUMBUS_3RDPARTY_INSTALL_DIR}/lib/python2.7.lib LOG_CONFIGURE 1 LOG_BUILD 1 LOG_INSTALL 1 @@ -246,18 +236,35 @@ elseif (CMAKE_SYSTEM_NAME STREQUAL Windows) ) endif () +###################### cppcheck ############################ + +if (CMAKE_SYSTEM_NAME STREQUAL Linux OR CMAKE_SYSTEM_NAME STREQUAL Darwin) + ExternalProject_Add( cppcheck + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/cppcheck + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${COLUMBUS_3RDPARTY_INSTALL_DIR} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + LOG_CONFIGURE 1 + LOG_BUILD 1 + LOG_INSTALL 1 + ) + +elseif (CMAKE_SYSTEM_NAME STREQUAL Windows) + + ExternalProject_Add( cppcheck + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/cppcheck + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${COLUMBUS_3RDPARTY_INSTALL_DIR} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + LOG_CONFIGURE 1 + LOG_BUILD 1 + LOG_INSTALL 1 + ) + +endif() + ###################### openssl ############################ if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") - if (CMAKE_CL_64) - set (OPENSSL_PLATFORM VC-WIN64A) - else () - set (OPENSSL_PLATFORM VC-WIN32) - endif () - ExternalProject_Add( openssl URL https://www.openssl.org/source/openssl-1.1.0h.tar.gz - CONFIGURE_COMMAND perl ../openssl/Configure --prefix=${COLUMBUS_3RDPARTY_INSTALL_DIR} --openssldir=ssl ${OPENSSL_PLATFORM} ${DEBUG_BUILD} -no-shared + CONFIGURE_COMMAND perl ../openssl/Configure --prefix=${COLUMBUS_3RDPARTY_INSTALL_DIR} --openssldir=ssl VC-WIN64A ${DEBUG_BUILD} -no-shared BUILD_COMMAND nmake INSTALL_COMMAND nmake install LOG_CONFIGURE 1 @@ -279,3 +286,36 @@ if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") ) endif () + +###################### llvm/clang ############################ + +if (CMAKE_SYSTEM_NAME STREQUAL Linux) + + ExternalProject_Add( clang + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/clang/llvm + CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX=${COLUMBUS_3RDPARTY_INSTALL_DIR} -DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS} -DLLVM_ENABLE_RTTI=ON -DLLVM_OPTIMIZED_TABLEGEN=ON -DLLVM_ENABLE_SPHINX=ON "-DLLVM_ENABLE_PROJECTS=clang\\$clang-tools-extra" -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} + BUILD_COMMAND ${CMAKE_COMMAND} --build --config $ --parallel ${PHYSICAL_CORES} -t install-llvm-libraries-stripped -t install-clang-libraries-stripped -t install-clang-headers -t install-llvm-headers -t install-clang-tidy-stripped -t install-clang-resource-headers + INSTALL_COMMAND "" + LOG_CONFIGURE 1 + LOG_BUILD 1 + LOG_INSTALL 1 + ) + +elseif (CMAKE_SYSTEM_NAME STREQUAL Windows) + + ExternalProject_Add( clang + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/clang/llvm + CMAKE_GENERATOR Ninja + CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX=${COLUMBUS_3RDPARTY_INSTALL_DIR} -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DLLVM_ENABLE_RTTI=ON "-DLLVM_ENABLE_PROJECTS=clang\\$clang-tools-extra" -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_GENERATOR_TOOLSET= + BUILD_COMMAND ${CMAKE_COMMAND} --build --config $ --parallel ${PHYSICAL_CORES} -t install-llvm-libraries-stripped -t install-clang-libraries-stripped -t install-clang-headers -t install-llvm-headers -t install-clang-tidy-stripped -t install-clang-resource-headers + INSTALL_COMMAND "" + LOG_CONFIGURE 1 + LOG_BUILD 1 + LOG_INSTALL 1 + ) + +endif() + + +######################## miniz ################################# +add_subdirectory(miniz) diff --git a/3rdparty/clang b/3rdparty/clang new file mode 160000 index 0000000..3ce9f5d --- /dev/null +++ b/3rdparty/clang @@ -0,0 +1 @@ +Subproject commit 3ce9f5d890a10bcb61043df6ffd11a752dc5677e diff --git a/3rdparty/cppcheck b/3rdparty/cppcheck new file mode 160000 index 0000000..f5b44b0 --- /dev/null +++ b/3rdparty/cppcheck @@ -0,0 +1 @@ +Subproject commit f5b44b0b0b59d6d3284357e08884ad8c59612599 diff --git a/3rdparty/miniz b/3rdparty/miniz new file mode 160000 index 0000000..8a7cf60 --- /dev/null +++ b/3rdparty/miniz @@ -0,0 +1 @@ +Subproject commit 8a7cf60c7af0153dca69c6f88a247a7220bd8003 diff --git a/CMake/AddExecutablePermission.cmake b/CMake/AddExecutablePermission.cmake new file mode 100644 index 0000000..84545a8 --- /dev/null +++ b/CMake/AddExecutablePermission.cmake @@ -0,0 +1,10 @@ +if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") + math(EXPR length "${CMAKE_ARGC} - 1") # ${CMAKE_ARGC} - 1 is the exact number of arguments + + foreach (item RANGE 3 ${length}) + File (CHMOD_RECURSE + ${CMAKE_ARGV${item}} + FILE_PERMISSIONS OWNER_EXECUTE OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ + ) + endforeach() +endif() \ No newline at end of file diff --git a/CMake/BuildInfo.cmake b/CMake/BuildInfo.cmake index 1275445..e8aedc2 100644 --- a/CMake/BuildInfo.cmake +++ b/CMake/BuildInfo.cmake @@ -11,4 +11,9 @@ add_custom_target ( set_target_properties (generate_build_info PROPERTIES FOLDER ${CMAKE_SUPPORT_FOLDER_NAME}) +cmake_host_system_information(RESULT HOST_INFO + QUERY TOTAL_PHYSICAL_MEMORY NUMBER_OF_LOGICAL_CORES NUMBER_OF_PHYSICAL_CORES) +list (GET HOST_INFO 0 PHYSYCAL_MEMORY) +list (GET HOST_INFO 1 LOGICAL_CORES) +list (GET HOST_INFO 2 PHYSICAL_CORES) diff --git a/CMake/Clang.cmake b/CMake/Clang.cmake new file mode 100644 index 0000000..1fd964b --- /dev/null +++ b/CMake/Clang.cmake @@ -0,0 +1,39 @@ + +set (CLANG_COMMON_LIBRARIES + clangMetrics + clangTooling + clangFrontend + clangRewriteFrontend + clangSerialization + clangParse + clangSema + clangEdit + clangLex + clangAnalysis + clangRewrite + clangASTMatchers + clangAST + clangDriver + clangBasic + + LLVMMCParser + LLVMMC + LLVMProfileData + LLVMBitReader + LLVMBitstreamReader + LLVMCore + LLVMSupport + LLVMOption + LLVMDemangle + LLVMBinaryFormat + LLVMRemarks + LLVMFrontendOpenMP +) + +if (CMAKE_SYSTEM_NAME STREQUAL Windows) + list (APPEND CLANG_COMMON_LIBRARIES version) +elseif (CMAKE_SYSTEM_NAME STREQUAL Linux) + list (APPEND CLANG_COMMON_LIBRARIES pthread z tinfo dl) +elseif (CMAKE_SYSTEM_NAME STREQUAL Darwin) + list (APPEND CLANG_COMMON_LIBRARIES pthread z dl curses) +endif () diff --git a/CMake/CodebaseOptions.cmake b/CMake/CodebaseOptions.cmake index 5dbe8ad..7427eb3 100644 --- a/CMake/CodebaseOptions.cmake +++ b/CMake/CodebaseOptions.cmake @@ -21,11 +21,6 @@ set (COLUMBUS_3RDPARTY_SOURCE_DIR ${CMAKE_SOURCE_DIR}/3rdparty) # Compiler warning settings if (MSVC) - # For ninja builds on windows we set the CMAKE_VS_PLATFORM_TOOLSET to V140 (VS2015) - if (NOT CMAKE_VS_PLATFORM_TOOLSET) - set (CMAKE_VS_PLATFORM_TOOLSET V140 CACHE STRING "" FORCE) - endif () - # Disable some common compiler warnings end enable parallel build set (EXTRA_COMPILER_OPTIONS "/WX /wd4996 /wd4267 /wd4786 /wd4244 /wd4068 /MP /EHsc /experimental:external /external:W0 /external:I ${COLUMBUS_3RDPARTY_INSTALL_DIR}/include") @@ -51,6 +46,7 @@ elseif (CMAKE_SYSTEM_NAME STREQUAL Linux) # Enable compiler warnings and use fPIC option set (EXTRA_COMPILER_OPTIONS "-Wall -Werror -Wno-unused-local-typedefs -Wno-unknown-pragmas -fPIC") + set (EXTRA_CXX_FLAGS "-Wno-overloaded-virtual") if (STRIP) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s") @@ -60,7 +56,7 @@ elseif (CMAKE_SYSTEM_NAME STREQUAL Linux) endif () -set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_COMPILER_OPTIONS}") +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_COMPILER_OPTIONS} ${EXTRA_CXX_FLAGS}") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_COMPILER_OPTIONS}") # Common global dependencies diff --git a/CMake/PlatformOptions.cmake b/CMake/PlatformOptions.cmake index f6e93ce..d37a2a2 100644 --- a/CMake/PlatformOptions.cmake +++ b/CMake/PlatformOptions.cmake @@ -1,24 +1,16 @@ -set (COLUMBUS_64BIT FALSE) - -if (((CMAKE_SYSTEM_NAME STREQUAL Windows) AND CMAKE_CL_64) OR (CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64)) - set (COLUMBUS_64BIT TRUE) -endif () - -if (COLUMBUS_64BIT) - set (COLUMBUS_PLATFORM_NAME x64) - set (VS_PLATFORM x64) - set (VS_PLATFORM_DIR x64/) - set (PYTHON_PLATFORM_NAME amd64) -else () - set (COLUMBUS_PLATFORM_NAME x86) - set (VS_PLATFORM WIN32) - set (VS_PLATFORM_DIR ) - set (PYTHON_PLATFORM_NAME win32) -endif () +message ("C++ Compiler:" ${CMAKE_CXX_COMPILER_ID} "-" ${CMAKE_CXX_COMPILER_VERSION} " " (${CMAKE_CXX_COMPILER})) +message ("C Compiler:" ${CMAKE_C_COMPILER_ID} "-" ${CMAKE_C_COMPILER_VERSION} " " (${CMAKE_C_COMPILER})) +if (NOT CMAKE_CXX_COMPILER_ID MATCHES GNU|Clang|MSVC) + message("ERROR: Not supported compiler!") +endif() +set (COLUMBUS_PLATFORM_NAME x64) +set (VS_PLATFORM x64) +set (VS_PLATFORM_DIR x64/) +set (PYTHON_PLATFORM_NAME amd64) if (CMAKE_SYSTEM_NAME STREQUAL Windows) set (SCRIPT_EXT .bat) @@ -33,7 +25,8 @@ set (COLUMBUS_PLATFORM_DEPENDENT_DIR ${COLUMBUS_PLATFORM_NAME}) set (EXE ${CMAKE_EXECUTABLE_SUFFIX}) -if(${WIN32}) +# Sets the msvs for the node-gyp required for the javascript +if(MSVC) if(${CMAKE_VS_PLATFORM_TOOLSET} STREQUAL "v90") set (MSVS_VERSION "--msvs_version=2008") elseif(${CMAKE_VS_PLATFORM_TOOLSET} STREQUAL "v100") diff --git a/CMake/UtilityFunctions.cmake b/CMake/UtilityFunctions.cmake index 722af76..148ef3f 100644 --- a/CMake/UtilityFunctions.cmake +++ b/CMake/UtilityFunctions.cmake @@ -99,30 +99,48 @@ function (add_copy_custom_target TARGET_NAME SOURCE DESTINATION) set_target_properties (${TARGET_NAME} PROPERTIES FOLDER ${CMAKE_SUPPORT_FOLDER_NAME}) endfunction() -# Add a custom copy target dependency to the ${TARGET_NAME} target, which will copy the ${SOURCE} to the ${DESTINATION}. -# If 4th parameter is set then directory copy is used instead of file copy. -function (add_custom_copy_target TARGET_NAME SOURCE DESTINATION) - if (${ARGC} LESS 4) - set (COMMAND copy) - else () - set (COMMAND copy_directory) - endif () + +# Add a ${TARGET_NAME} named custom copy target, which will copy the ${SOURCE} +# directory to the ${DESTINATION}. It recognises changes in the source directory +# except the file deletion! +function (add_copy_custom_target_dir TARGET_NAME SOURCE DESTINATION) + file (GLOB_RECURSE SOURCE_DEPS CONFIGURE_DEPENDS "${SOURCE}/*") + list (APPEND SOURCE_DEPS ${SOURCE}) + + foreach(SRC ${SOURCE_DEPS}) + string(REPLACE "${SOURCE}" "${DESTINATION}" REPLACED ${SRC} ) + list (APPEND OUTPUTS ${REPLACED}) + endforeach() add_custom_command ( - DEPENDS ${SOURCE} + DEPENDS ${SOURCE_DEPS} MAIN_DEPENDENCY ${SOURCE} - OUTPUT ${DESTINATION} - COMMAND ${CMAKE_COMMAND} -E ${COMMAND} ${SOURCE} ${DESTINATION} + OUTPUT ${OUTPUTS} + COMMAND ${CMAKE_COMMAND} -E rm -rf ${DESTINATION} + COMMAND ${CMAKE_COMMAND} -E copy_directory ${SOURCE} ${DESTINATION} COMMENT "Copying ${SOURCE} to ${DESTINATION}" ) - get_filename_component (CUSTOM_TARGET_NAME ${SOURCE} NAME) - set (CUSTOM_TARGET_NAME ${TARGET_NAME}_copy_${CUSTOM_TARGET_NAME}) add_custom_target ( - ${CUSTOM_TARGET_NAME} - DEPENDS ${DESTINATION} + ${TARGET_NAME} + DEPENDS ${OUTPUTS} ) + set_target_properties (${TARGET_NAME} PROPERTIES FOLDER ${CMAKE_SUPPORT_FOLDER_NAME}) +endfunction() + + +# Add a custom copy target dependency to the ${TARGET_NAME} target, which will copy the ${SOURCE} to the ${DESTINATION}. +# If 4th parameter is set then directory copy is used instead of file copy. +function (add_custom_copy_target TARGET_NAME SOURCE DESTINATION) + get_filename_component (CUSTOM_TARGET_NAME ${SOURCE} NAME) + set (CUSTOM_TARGET_NAME ${TARGET_NAME}_copy_${CUSTOM_TARGET_NAME}) + + if (${ARGC} LESS 4) + add_copy_custom_target(${CUSTOM_TARGET_NAME} ${SOURCE} ${DESTINATION}) + else () + add_copy_custom_target_dir(${CUSTOM_TARGET_NAME} ${SOURCE} ${DESTINATION}) + endif () + add_dependencies (${TARGET_NAME} ${CUSTOM_TARGET_NAME}) - set_target_properties (${CUSTOM_TARGET_NAME} PROPERTIES FOLDER ${CMAKE_SUPPORT_FOLDER_NAME}) endfunction () diff --git a/CMakeLists.txt b/CMakeLists.txt index 14d2441..a5d3a5a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,11 @@ -cmake_minimum_required (VERSION 3.16.0) +cmake_minimum_required (VERSION 3.19.0) # Set the default build type to release if (NOT CMAKE_BUILD_TYPE ) set (CMAKE_BUILD_TYPE Release CACHE STRING "Build Type: Release or Debug" FORCE) endif() -project (OSA VERSION 4.1.0) +project (OSA VERSION 5.0.0) set (EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) set (CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${EXECUTABLE_OUTPUT_PATH}) @@ -19,11 +19,21 @@ set (CMAKE_SUPPORT_FOLDER_NAME CMakeSupportTargets) set_property (GLOBAL PROPERTY USE_FOLDERS ON) include (BuildInfo) +include (Clang) include (UtilityFunctions) include (PlatformOptions) include (CodebaseOptions) include (Common) +add_subdirectory (cl/CAN) +add_subdirectory (cl/CAN2Lim) +add_subdirectory (cl/CANConfig) +add_subdirectory (cl/CANLib) +add_subdirectory (cl/CANLink) +add_subdirectory (cl/ClangTidy2Graph) +add_subdirectory (cl/Cppcheck2Graph) +add_subdirectory (cl/DCF-CPP) + add_subdirectory (cl/DuplicatedCodeFinder) add_subdirectory (cl/ESLint2Graph) add_subdirectory (cl/FindBugs2Graph) @@ -41,16 +51,36 @@ add_subdirectory (cl/LIM2Metrics) add_subdirectory (cl/MetricHunter) add_subdirectory (cl/PAN) add_subdirectory (cl/PAN2Lim) +add_subdirectory (cl/ParamCheck) add_subdirectory (cl/PMD2Graph) add_subdirectory (cl/Pylint2Graph) add_subdirectory (cl/Roslyn2Graph) add_subdirectory (cl/Sonar2Graph) +add_subdirectory (cl/OpenStaticAnalyzerCPP) add_subdirectory (cl/OpenStaticAnalyzerCSharp) add_subdirectory (cl/OpenStaticAnalyzerJava) add_subdirectory (cl/OpenStaticAnalyzerJavaScript) add_subdirectory (cl/OpenStaticAnalyzerPython) add_subdirectory (cl/UserDefinedMetrics) +add_subdirectory (wrapper/AbstractWrapperLib) +add_subdirectory (wrapper/AnalyzerWrapperConfig) +add_subdirectory (wrapper/ArWrapper) +add_subdirectory (wrapper/AsWrapper) +add_subdirectory (wrapper/ClWrapper) +add_subdirectory (wrapper/ClangWrapper) +add_subdirectory (wrapper/CopyMoveWrapper) +add_subdirectory (wrapper/EnvironmentSetup) +add_subdirectory (wrapper/exewrapper) +add_subdirectory (wrapper/LdWrapper) +add_subdirectory (wrapper/LibWrapper) +add_subdirectory (wrapper/LinkWrapper) +add_subdirectory (wrapper/LnWrapper) +add_subdirectory (wrapper/VsbuildWrapper) +add_subdirectory (wrapper/WrapperEnvironmentConfig) + +add_subdirectory (lib/archivecpp) +add_subdirectory (lib/clangsupport) add_subdirectory (lib/common) add_subdirectory (lib/controller) add_subdirectory (lib/csharp) diff --git a/OpenStaticAnalyzer/CMakeLists.txt b/OpenStaticAnalyzer/CMakeLists.txt index 3202ae5..111ff51 100644 --- a/OpenStaticAnalyzer/CMakeLists.txt +++ b/OpenStaticAnalyzer/CMakeLists.txt @@ -13,6 +13,7 @@ endif () add_custom_target ( ${OSA_TARGET_NAME} DEPENDS OSA-Java + DEPENDS OSA-CPP DEPENDS OSA-Python DEPENDS OSA-CSharp DEPENDS OSA-JavaScript @@ -52,6 +53,7 @@ function (copy_licenses) ) endfunction () +add_subdirectory (cpp) add_subdirectory (java) add_subdirectory (python) add_subdirectory (csharp) diff --git a/OpenStaticAnalyzer/cpp/CMakeLists.txt b/OpenStaticAnalyzer/cpp/CMakeLists.txt new file mode 100644 index 0000000..302a7a3 --- /dev/null +++ b/OpenStaticAnalyzer/cpp/CMakeLists.txt @@ -0,0 +1,124 @@ +set (PACKAGE_LANG CPP) +set (OSA_TARGET_NAME OSA-${PACKAGE_LANG}) + +add_subdirectory (doc/usersguide) + +add_custom_target ( + ${OSA_TARGET_NAME} +) +set_visual_studio_project_folder(${OSA_TARGET_NAME} FALSE) + +file (MAKE_DIRECTORY + ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/Demo + ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/${CMAKE_SYSTEM_NAME}Tools + ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/${CMAKE_SYSTEM_NAME}Wrapper/WrapperBins/Tools + ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/${CMAKE_SYSTEM_NAME}Wrapper/WrapperBins/Tools/cppcheck +) + +# These functions copy the SOURCE file into different directories of the OpenStaticAnalyzer package. +# The second parameter is optional. You can set the name of the target, which will be used for generating the SOURCE. +# The third parameter is also optional. You can set a different name for the SOURCE on which the file will be created in the tools directory. +function (add_custom_generated_copy_dependency_to_root_dir SOURCE) + add_custom_generated_copy_dependency(${OSA_TARGET_NAME} ${EXECUTABLE_OUTPUT_PATH} ${OSA_PACKAGE_DIR}/${PACKAGE_LANG} ${ARGV}) +endfunction () + +function (add_custom_generated_copy_dependency_to_tools_dir SOURCE) + add_custom_generated_copy_dependency(${OSA_TARGET_NAME} ${EXECUTABLE_OUTPUT_PATH} ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/${CMAKE_SYSTEM_NAME}Tools ${ARGV}) +endfunction () + +function (add_custom_generated_copy_dependency_to_wrapper_dir SOURCE) + add_custom_generated_copy_dependency(${OSA_TARGET_NAME} ${EXECUTABLE_OUTPUT_PATH} ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/${CMAKE_SYSTEM_NAME}Wrapper/WrapperBins ${ARGV}) +endfunction () + +function (add_custom_generated_copy_dependency_to_wrapper_tools_dir SOURCE) + add_custom_generated_copy_dependency(${OSA_TARGET_NAME} ${EXECUTABLE_OUTPUT_PATH} ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/${CMAKE_SYSTEM_NAME}Wrapper/WrapperBins/Tools ${ARGV}) +endfunction () + +function (add_custom_generated_copy_dependency_to_cppcheck_dir SOURCE) + add_custom_generated_copy_dependency(${OSA_TARGET_NAME} ${COLUMBUS_3RDPARTY_INSTALL_DIR}/bin ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/${CMAKE_SYSTEM_NAME}Wrapper/WrapperBins/Tools/cppcheck ${ARGV}) +endfunction () + +add_custom_generated_copy_dependency_to_root_dir (OpenStaticAnalyzerCPP${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (rules_cpp.csv OpenStaticAnalyzerCPP) +add_custom_generated_copy_dependency_to_tools_dir (CAN2Lim${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (Cppcheck2Graph${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (Cppcheck.rul Cppcheck2Graph_copy_Cppcheck.rul) +add_custom_generated_copy_dependency_to_tools_dir (DuplicatedCodeFinder_cpp${EXE} DuplicatedCodeFinder_cpp DuplicatedCodeFinder${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (DCF.rul DCFRulCopy) +add_custom_generated_copy_dependency_to_tools_dir (ClangTidy2Graph${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (ClangTidy.rul ClangTidy2Graph_copy_ClangTidy.rul) +add_custom_generated_copy_dependency_to_tools_dir (GraphDump${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (GraphMerge${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (LIM2Metrics${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (MET.rul LIM2Metrics) +add_custom_generated_copy_dependency_to_tools_dir (MetricHunter_cpp${EXE} MetricHunter_cpp MetricHunter${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (MetricHunter_CPP.threshold MetricHunter_cpp_copy_MetricHunter_CPP.threshold MetricHunter.threshold) +add_custom_generated_copy_dependency_to_tools_dir (UserDefinedMetrics${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (Sonar2Graph${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (LIM2Patterns${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (Patterns LIM2Patterns Patterns DIRECTORY) +add_custom_generated_copy_dependency_to_tools_dir (Lib LIM2Patterns Lib DIRECTORY) + +if (CMAKE_SYSTEM_NAME STREQUAL Linux) + add_custom_generated_copy_dependency_to_wrapper_dir (ArWrapper${EXE}) + add_custom_generated_copy_dependency_to_wrapper_dir (AsWrapper${EXE}) + add_custom_generated_copy_dependency_to_wrapper_dir (CopyMoveWrapper${EXE}) + add_custom_generated_copy_dependency_to_wrapper_dir (ClangWrapper${EXE}) + add_custom_generated_copy_dependency_to_wrapper_dir (LdWrapper${EXE}) + add_custom_generated_copy_dependency_to_wrapper_dir (LnWrapper${EXE}) + +elseif (CMAKE_SYSTEM_NAME STREQUAL Windows) + add_custom_generated_copy_dependency_to_wrapper_dir (ClWrapper${EXE}) + add_custom_generated_copy_dependency_to_wrapper_dir (LibWrapper${EXE}) + add_custom_generated_copy_dependency_to_wrapper_dir (LinkWrapper${EXE}) + add_custom_generated_copy_dependency_to_wrapper_dir (VsbuildWrapper${EXE}) +endif () + +add_custom_generated_copy_dependency_to_wrapper_dir (WrapperEnvironmentConfig${EXE}) +add_custom_generated_copy_dependency_to_wrapper_dir (exewrapper${EXE}) + +add_custom_generated_copy_dependency_to_wrapper_tools_dir (AnalyzerWrapperConfig${EXE}) +add_custom_generated_copy_dependency_to_wrapper_tools_dir (CAN${EXE}) +add_custom_generated_copy_dependency_to_wrapper_tools_dir (CANConfig${EXE}) +add_custom_generated_copy_dependency_to_wrapper_tools_dir (CANLib${EXE}) +add_custom_generated_copy_dependency_to_wrapper_tools_dir (CANLink${EXE}) + +add_custom_generated_copy_dependency(${OSA_TARGET_NAME} ${COLUMBUS_3RDPARTY_INSTALL_DIR}/lib ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/${CMAKE_SYSTEM_NAME}Wrapper/WrapperBins/Tools clang clang clang DIRECTORY) +add_custom_generated_copy_dependency(${OSA_TARGET_NAME} ${COLUMBUS_3RDPARTY_INSTALL_DIR}/bin ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/${CMAKE_SYSTEM_NAME}Wrapper/WrapperBins/Tools clang-tidy${EXE} clang clang-tidy${EXE}) + + +if (CMAKE_SYSTEM_NAME STREQUAL Windows) + add_custom_generated_copy_dependency_to_wrapper_tools_dir (ParamCheck${EXE}) +endif () + +add_custom_generated_copy_dependency( + ${OSA_TARGET_NAME} + doc/usersguide + ${OSA_PACKAGE_DIR}/${PACKAGE_LANG} + UsersGuide.html + ${OSA_TARGET_NAME}-UG +) + + +add_custom_copy_target (${OSA_TARGET_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/demo/analyze${SCRIPT_EXT} ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/Demo/analyze${SCRIPT_EXT}) + +if (CMAKE_SYSTEM_NAME STREQUAL Linux) + add_custom_copy_target (${OSA_TARGET_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/demo/build${SCRIPT_EXT} ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/Demo/build${SCRIPT_EXT}) + add_custom_copy_target (${OSA_TARGET_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/demo/softfilter-linux ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/Demo/softfilter) +elseif (CMAKE_SYSTEM_NAME STREQUAL Darwin) + add_custom_copy_target (${OSA_TARGET_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/demo/build${SCRIPT_EXT} ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/Demo/build${SCRIPT_EXT}) + add_custom_copy_target (${OSA_TARGET_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/demo/softfilter-darwin ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/Demo/softfilter) +elseif (CMAKE_SYSTEM_NAME STREQUAL Windows) + add_custom_copy_target (${OSA_TARGET_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/demo/build-win-x64${SCRIPT_EXT} ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/Demo/build${SCRIPT_EXT}) + add_custom_copy_target (${OSA_TARGET_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/demo/softfilter-windows ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/Demo/softfilter) +endif () + +add_custom_extract_target ( + ${OSA_TARGET_NAME} + ${CMAKE_CURRENT_SOURCE_DIR}/demo/log4cplus-1.1.0.zip + ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/Demo + ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/Demo/log4cplus-1.1.0 +) + +add_custom_generated_copy_dependency(${OSA_TARGET_NAME} ${COLUMBUS_3RDPARTY_INSTALL_DIR}/bin ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/${CMAKE_SYSTEM_NAME}Wrapper/WrapperBins/Tools/cppcheck cppcheck${EXE}) +add_custom_generated_copy_dependency(${OSA_TARGET_NAME} ${COLUMBUS_3RDPARTY_INSTALL_DIR}/share/Cppcheck ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/${CMAKE_SYSTEM_NAME}Wrapper/WrapperBins/Tools/cppcheck cfg cppcheck cfg DIRECTORY) diff --git a/OpenStaticAnalyzer/cpp/demo/analyze.bat b/OpenStaticAnalyzer/cpp/demo/analyze.bat new file mode 100644 index 0000000..296fd2c --- /dev/null +++ b/OpenStaticAnalyzer/cpp/demo/analyze.bat @@ -0,0 +1,4 @@ +@echo off + +..\OpenStaticAnalyzerCPP -projectName=log4cplus-1.1.0 -buildScript=build.bat -resultsDir=Results -externalSoftFilter=softfilter + diff --git a/OpenStaticAnalyzer/cpp/demo/analyze.sh b/OpenStaticAnalyzer/cpp/demo/analyze.sh new file mode 100755 index 0000000..5b0d5c6 --- /dev/null +++ b/OpenStaticAnalyzer/cpp/demo/analyze.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +../OpenStaticAnalyzerCPP -projectName=log4cplus-1.1.0 -buildScript=build.sh -resultsDir=Results -externalSoftFilter=softfilter diff --git a/OpenStaticAnalyzer/cpp/demo/build-win-x64.bat b/OpenStaticAnalyzer/cpp/demo/build-win-x64.bat new file mode 100644 index 0000000..c96f275 --- /dev/null +++ b/OpenStaticAnalyzer/cpp/demo/build-win-x64.bat @@ -0,0 +1,5 @@ +@echo off + + +devenv log4cplus-1.1.0\msvc10\log4cplus.vcxproj /upgrade +msbuild log4cplus-1.1.0\msvc10\log4cplus.vcxproj /t:Rebuild /p:Configuration=Release /p:PLatform=x64 \ No newline at end of file diff --git a/OpenStaticAnalyzer/cpp/demo/build.sh b/OpenStaticAnalyzer/cpp/demo/build.sh new file mode 100755 index 0000000..2d8cf0f --- /dev/null +++ b/OpenStaticAnalyzer/cpp/demo/build.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +cd log4cplus-1.1.0 + +make distclean + +export OSA_DISABLE_ANALYSIS=true +./configure CXX=clang++ CC=clang +unset OSA_DISABLE_ANALYSIS + +make diff --git a/OpenStaticAnalyzer/cpp/demo/log4cplus-1.1.0.zip b/OpenStaticAnalyzer/cpp/demo/log4cplus-1.1.0.zip new file mode 100644 index 0000000000000000000000000000000000000000..d34df68584e0f580d90763b3a6e156570e68706d GIT binary patch literal 903303 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⪚?6+xy7gU0D-lQBur_|iUI^Ds_EO+p-bVSSRV<2L6Sm6hySx-y&10pmF%7T# zG({lRBrCayV3 zv!}dGgIZp~D!Mc_AilQGiFYbMVtc2Fv?e61laa^&jW1Iq_CQk-0HT{onfM6ss=r0n z;Cral@>Q@!m!^AbngtV(BMgBTmj3cZB+k0g>KIUB#f~z1EuMKBj%C&N9kDNXof&oI z3H4a0;R#)bNRRBT5;a3kYZ4MRx+IMXSof*tADYkhCnQW|7z;u#-&OMRE2X8bha#I;@l8 zf%CliG<;-gs39aN%S1Rnze&XesV7{aa-el3+85FscmI%fA}Enf^-kXJGgTFn%fP^R zi_qWuJ1_W3p7C88z0trys<&>~r{G1Y^%oI|QGOuu-W+~oq2V&>%$-(4wX)ZCI44AV zmAIuLG;VS@vR2<4sK)tLT{%+re*ea>w*WS$_PrS(=u31a^~BJOhE!))>m>Q z~hJ2RnFHC_q3}hW{H={~y!#wXU@zh&a~wjv;dj)~1>6EpNa;2u58Q zNE?pn0T5^$Lr-UmF2L~iq2HChN6nUPKFglZDBJti*Q5TSR!!S_M!-4H($di&deiS~ zMv-J0HXYmjIm5qktt=fHaq|)+3QFd4-7t_66PMh9K1@*OC!Qv5hV_1B88`Y>#3G#z z;h>Il$Ln-mKDT+x|MC6u-S9*djqR`%l=VK)!8mQ;OW(YDJOo!Q}uq` zi-e$jNKEb@kGbF5&mo}fwPDJcp(s%#Jc9-eLV~aK-zfs0vUUZ7ikGT*bB^C3X zbHs8#ZzI^U8BM60fsDh#mJceY4!LlJ1zi+ko1}PR0H*Sk(M4DZ51kI8*4@a3&I!!M z9E%;gmF_Paa^LKuuf79Tf~Xg{zz{{TsU~_49tLU| z4qAa%Jzg3?iwU5szft$0j|Qc(At)mXDt~=8n##2)Nr|V z$Bxd}$l|v$Kme;{Nj5@1bIM>S=MFCH47P@#Wu7;rb%9pOwIT*QSRn8vUXu|^-++qJ z3$c<$9=a+OVG3e_6@er;uLe#;%PL#q44$WC;`d}t0oSO(yV@heh0drTSt?~;EfB2j z#q&N;rJ-;g2T|DBj*V#Wz&iG2=JEnZ8+9YSTH==NW^1c{kw!IDV}7816CjWRZPTyn zPmWoG3k*bjY^#a#0JL~UCX|mZ{8g!BYQqG7cBXNd(u4~6pBJno@Iwr;ogYmfee_S> zrIc!&SFG8<5b9Q`(UDMp2zNE=kJ0L}j#uZVWb8_XzEBaa2n`uarDy4j{`xR94L&#q zZi~4=t43*umc=6_Zq(B?J=#jcg_JR;N4VMZ)c73;r`qt4gR+cbzN-s6!IRqO?)O(Qjw3;c3f}szz)@cPue`{=@(387*O>yN~wEk zXq2dPcDf+vyo}((9g$`hsIb{G;$!ox7}>$#1~Y!N8af&k%xe(4zO|(g;579U@Gjq? z0=AlzTC8H{01`B^Jj`!gp~jrVzHyL4x(YbD@G{0=I>mMBM)?MJ2s-=xj)SJqlMBG7W`I3&Lh@uHrmG+;e)}}a{EpcWzn9NrUI5Of0QR%%fr>U9_Nt5BL z$KnavR01LWd)DxN5;e)9BNd4TR&5tG3w+=c)(ojX)t;H5#>y|tH3pmEiIM#GH5?Y2;Q$wg2ODbvn#v_mmlxDs8jhZf;X%67Ygl6o%Cyi56;;ek0Sgs9=(>r z9D1wIF?IAI65THQn-oSV)*{~qp@=s$>aSZjh1ir8dyFw6!IL-~r#`pI4!$j#xc(!| zd%9NcLC&2;ozJQR5^o>H0GRoU(aBbX1TN(<<~qZaq$F9}zve;o`de1Ohe!U%(0auYK|;piSwjEc)$3 zCQhUDXATxyjAqSEO{Qu!1FS3KkrkYKxARwI7`p8x3Fk=)I0VOlsQ6RrS3R&;sf#0x zK1xlMjw!7y9TK5Uh=khb5D+9=fzzSRHIyZCx~r2NxBnVJUMg0miDU*=wbE`Jk0Nxu z#3S?HeJ%C%s{sa?jfZxUc*eC1ud(VXSvY)5x>QD(Mie-TJS-KOE%v0!qgd%HR*wJ= ztp9TOacf9foiJmvrGCyr5k#!^dG_PgFtc&4^7vcPy0o9199Z5%)FQlt33XjYdtirX zelZtPs8a2O--{KA55hl4hfOg^*2S-EyN_pTAU0*x5Ee>a@8EIpR7R=1WWqp_097JP zc4W-VOEJ@p3KJ_U?v7g13?Y{BXNS*mi!Q&g0$Bw&JvY99AcEW>d(m@(1wa8f=c_OD z^8`rKs&j_5_ac=@1v!37E%)`@+qv;y{do(Z*WPjBO$?Q}!71qW97dWG@t0|?ZGfU_ zEkNN(lbt|hFHx-k$doIZD6!x76k3pmnulpi8IY_(onS-%N~6WaH7b?Cv8k|8_4!Ti zLkmMn^fi`BjUTVPqAVh5Ck~&tLJw+(`;}}+h*&7}Oas7H$hL)W!4Uu=x2Kjhyj(8V zdl+(6(GgdS1_$F2s-Xj-%g6*A5uZ_j!Y(nX8W)k}%wfCZ--wlypLF+Ec{$a&Vf`In zYE!Kj;iec}4~o}{e21eeh0g(FiKVb*GM zH@Dq3@iS@~Fx{{Muwgi1nT$QQvfj7C@Tb;+##9>zDlpCF>E@v+$K|%$k#D+!3z^=b zs|yS95xS>XlT}pN#J3Hf!|a53pNv5nh3xrDua!q+h%=!96}fAy0GNU6 z7OQ=5qSQHOQ&g|7s1nRceoZUvX%XMLw1`pyV+<>!Th#+ZBj{|jtS>Z)bgWu`W0;VU z%y1$|ek4X}H^Bu2xS`Yd53b=Ib*ebtl+OlsvAddMq+-L51OvT7?N3~f#)WXaE#l@H zo^;tyjM=Yl?VL}gKp-R|FyWT-Om_u`qglHzhvOz?(6ozPif9iBY9a0?#3k5aFauZ- zm5IPl@WGW=&iD_YFMOfG`+=BW^-!S>uq0;|GPc@KiBWoam0FHt#b;7=RBNo@*u#cV zrys91O*Yq=7%d!1U`%bI>}`UxV>~J()8^z0lw~?-#1CeH-v*Y>;v(c=na}JhFr?JTpsrW-0!iNJIEri|AJyuC9LI^e;upj*@jxJCR@U7M?>@{{DrxMq4kG zN^3**fh0GC6fcM8a~8V3I#~WPHKsd1wTSfq4}Lpq{9)I$gI*AZP!<;YUWu zk9*(>Ex&G6;nx!i*nV`28t39L4&;)gl?{co7+ZZrHFo%YD5j^)mYth+j(QX`x*)Jh zg&eM?F6z{SAWzht8uO;L1H4E6DHeLUvxk%s60IjMoqQ)nWz-#d0#)^(1!>$s4ILUM z!1zNR=|u)Iu7d$FQY$+)>>3H&#}>)b7+~D3C-A2*!vKZ%YE=X3`xpXo$7di?v-o#m z9uRfdm~7SuvGQvEfpci*w$o~s^^Y4;Y8Z`M)3|Fv$cD7#S80T0{gOpJ+9+xmPr1@y zI2|f4FT^&l%lgd{hNRvOVW?*^wD0rjU9{Fze*(GQ+eQh-9jNW&SGor>8wVEWTLBNT z$nn_y`fmiTJIMq|dO1G$d-e`N3}T#5Q-o6DI31s^h3E<@;^I+hRql$+ir83dMc3lSZ6dN* zWKglT8xk`*`vVH4jTn04mei?mh-sGm!`wg*7L)4wZ?8Y!-+$qIzav#3-tB~sZyN0{ z@_hU)u2%}HwRjqUi|~rsbI;tFIK$Od%7>%-R30pKW}{O&or5HSWbcG~bK)#fuK&07 z%=aL;Q#2Ml?FwNhjjLj_tae>oH}pz4tqXGvBTN9-r}qbOp=O zy`@Rx4$X<5`+Jcfc&&5`*`GZirlJ6pvU6=p!Uy%ZWy&^sH!`JqHYI~AE&7uhNZEsR z#mEqqt+@eW&)r^zp&bIJ7_25uFI^fl_v!dn)v=%?dOw5xAb!}eD9^h%IxND@_hmOM z&E4T%hapOo;jvEMC$&gXKfQSpC#sHM%`|yI4;JlM9dWz6>jjh0TTd{%o%!hRNl*52 zhLsqFFeCX0iofP_-n4}!`tk5%2>otTQ(CvDXB76AEoT>CtocwR<;{sD9A!hpNAvX1 zML3uB5v+{rwpTCo9VC00Ri#okkj<6WZq&6;v$a;={Wn}Ze&ZXCuY={@`ICASD;aZ{ zp8VIr(Dv#o;+p`>Qi2B>UY!MvZFOAC8$QiP3Ty=dT+S zP9^FKE}Bx8J(N<3G{E$uQV7xFs>Imr>(o62=hGyTitmAhSCdEKu!+$p9-0^QUaY`? zei44XcVzjb;)@POAgTgN5?n`WK@5DMXO#>>{gUzE!O(oG65tc`q21W=EJm?*cyGd0 zoarG^*L#^hw22cZpnrAJoU(L(+VtkBpwF!9`fJjh9ygr8?_l(1%}N=qeh{IzJ1@U` z*e)ERsP4*6>;%oSv4TmHYwYZ1lbYbW|-QI#8u%5{HdYq)Um$oOk0{4No z4qVNYp;%Z|`xrqX{Bnkbf6Lo~&j26;;$=dYnMUf~1+#^0^>s15!6HU1f0LCzK-?3vrGQ=JXD{EGb|&Z`H%(dc!SgO{l(bHh!yV|f}rdh8{~lk37MRHL7D^Y z_qo8Y2ixfg(tpxO-5+!FhXWb>5aQl~y&VkJ*Fbubpbo5+(w;t}f?_h}B6dIS*Qam6 z_4Va?^LBURF%}#FTsko0>GBU3QKSMjmh3bjTp%#X_o0hW?>SB6qObxp2=-umgYtv+ z?&8m3X*gE@uCvQ#v_A2j0C#~uimBh!aX77QcUIHxprYMGOS_7cavLt`+?)HqFHiJ( zM-+DM-RUjK{`VXHzvfA8)tvwD3+DdYv%fE?XzAQddOHv2HXS`?Y0|d;U+Ai%nlfH- zFD1JCA5<044>t?Re?eFM@BuLYMBOe4s2H9Hy9)bwv$3`F*! zUbk~n^JV{(Lw%|lG)4P{jh>lBb>YI%X^8xgGs#md?Tzklp#P-b)Z>Tv0SQl9ML(X+ z{TR-F@$i2LNdA{E!N5i)mH{D<9yR#+D-s?ayNI?L7HuJZ0keS27O-~b-H^H#*t^}B zKQS?}>6T`M)oUEReBpg?p*)*x3;iZJx=SmmdMrX(n9PF>lljaqgAn0t3adrlW-j5f zek{Tf`oHuL|HHup355Q`!Sh!`%QE7JRt3!A|Hn5A+e}zr+X^Z1Mv#5u9h<-S+wE}O`8IcM~xT?KsW|6NkQA9u3slp(=~~FZQVYHX3J(y zM$Z2XpUJ;$t0m6^c>t$g>|pD&u&;5c4~9-3{VmQ2bbsUN%IVn3>&7ukO>;{-1(z-3 zNd;8dz*En|PJwo9av2E!OY_%y=+dU(%eIM&)i45lwb(5W*P+}x?>x9diMu(i*9(tk z_z_)X;oVXhgu*wh)XI9R}87WT&@)_7AvBL0`^Z&f0QBmTw` zL!z_DYiO}nvym}D>>6Ng=R;-!j*udH;A7FiAm5_r!8C;q^iZNh9K6Q5|Be*chkKzS zu|y^4?-T|O$KyU1bNJA02<4e|JYf1NJ>@eANnXun=fZ;1_$TEzy{Bw_T4O)QJYxfa zXx`7fUo5UYM>RL?R@7>Idl&J1ogiiM@4kHY!l3N5h&-*Xx~;`$1H$}{?>hpA9r1yn z$}JB=#z3RUE*j_U{Gf5Q^0M`^5qkSY`S=K2xq^Vbw$7W-lY1>6!;UY{qg3;Bbe`)x zgW#EKIZj|VCzg)!PLAm6GzaBYp{)K^&9bYr;MwhVnA2XlKh|r8`FA*AzN7gKBIqMI zAdA8QV|g@8M~WCfe-yf~0v!^D`oi1V_H-Jsd2JIUBa!)j%u*YY+9_1%S59G9OXLfl zH}HBFg$#M%ca@3yvd}DbJ>?L{+`x<#?lB0pzBU_BR-aCB&eOYTGNJ@ZQMI zm_Pq*hCGp(@pc~oK!Pm@@+TeXc1)!!r4Qvkk?_ZO7U|Ho(rsDGYn$SfDTW-F_2zjZ zO&B#jJ?gJ1-W{Xf>U|bV6g5_I{(WQ)3%FEbZb=escsXwilG~)?`t0|pdv|?QaUejt z$_M?shW+$*2;y~4!-~x%fJwgPef5{=xtYaUffO73FN0wUnAi8qN^#fO^VD0-1g>F{ z<;+!{9^8HSRA-RE`QE^1^E~I}LxiBecz9z{-%C`#EqX8t{(y=++XK4q>gm&4S`CaE zD%f0y)8h5Y>z2Mbh;hcbZDn%ci6h0#C1-k^K&U>)GYak`z?`$`x2!b%QI_mpO=%Ap zIi!B39_*&UcgOsY?tQ8hA8zNg|IYD&`^9!`8SX({wmXe<(OGtG5c}oUp-COgD{uK_ zBWR=myr(MG`$RkJjQjBAV7gzQeDBTX1X?E?U>_4x4JsmOObvzUhSoK5DE3L*9N#tpc+7-Qb&by%M^&m2gUSrs%F7# zzfxs)v!Q;`bi@$Xi|Emdw~07Q+FJaeZvXTHI>gYY6vef2|8<|DS0e2hVH~Z@fZ^E{ zNaLsW;D{ArIPp0r(FCuQ=uc5S!=J^e%Bk_<#c0=_mRan(v@_LUZ1Bl+N}JL%#ju@v zT*MvS&Joxs{lgvBq%B%xt!cj%YLA&1z^Ng6o^tA^8V{0GF~Z1pC(5K}njg|$I+Hln z{~nT{qX>jIPvdY3k>^TFJ6>VBz7+*iMy4qs#k7nPi-Xfi)pFWqlF~~1Z)~_Uf4HI8 z3B3E<7e~o^e16rp%m*$igO2N}ev$7SHi5$PCWTKkXu0zq>%`?@U^MO;Bxi8xUt)+v z+)`PSrDWe>wvMc!btrP=M1%L6vJW!#`6Rk}EIG%+1Ut+>nmkp10|;JQxrS=`^VN5l8Y=! zgOteh{_!KS{ga}$+z3Wr>d?E*IVsaxwy&|6PvdTYLi_7T`xfVGf}P94Tq#gzI_8s0 z$x8$Dx3m-=t2M2>F0)ZZ$r4o&XuLKf81h&xBHx!hH8$EZJ^>7014*8%toT!_EEi5Sx(lHc#x}NC0Kc8w5jyes36CVwa|D>*}1W4w>a&4 zaEYa9T#R7EqWa@bsj3(8U%-c&RsGA2DM7*Enj7Cj58rQe1iM_kQ~=Y>y`GP*X^9-C z*|E+_=DsJ#SFJpaH-aMu^hHV_T9gF5sU9?s_V*7O?L-Sac{q!U#AKu47N0iNp+VE$+9HX8O|=?Bnb*Q-^?E|IgOk_jb- zw=uRx?{)32C`*{?F|)uWHo;w-heq1S!^4A&ytpTj!qz=hz4~k@A^~miaX7w*qipIX z(dNHHa5TWO4}jH>SM=*(We1X1cyR(&gcSx1tH5q3=oQ$gl3|V_0ybP?CK9VCiKF;g z?#h8AYBX@d_AJck0pIGhSA!iPa{0{6cz=MG?R)T+lJe4-9#PxwoVAM;DP_2BOycT{Bz>glWMsuK9}-R#Ua>dE~P_gv9S z4E3RbN!qQx@1*aKXjCkcb2lY1b!6yNf>pPu(?0AJ-gclh*l1t4rfZy@43;a%)a>(| zyyGP7CE*;nOxs|+FM?419>)hGhZDDPaHk;~P@dmOirz1Slf0a6&UY%OyJ%Q9$jZV> zT1C+(b~iQ+)*Cw9p~F?yB^%JQA|J5>(BZB1nbUN{BT| zIkD=o26p~h6`9?+a-qstjC0!wqytxk*OH6kQEVDWM(4EB$+$r2uit+(>5o65N4I> zdjq{jSmU_)(6kQ$xpCKjNU{VB7N62ht+pMj*_OSN5>lmT=}Ve4&mT{@y-C%RV6?(d zeuCHFyhwWt_{gZRW45d0t3br8*?>uu+W?xm=d4}`Y%5#DxY0soj(z?-sVAnPrf{W? zJUdVcOt`*)J)^~DzPP5SS>N3LQzglw#|z{{6oeX83RMJ^gd=p}x!7Gozh|5*uzcTK z;E3(7LWDYQ6RE!t2KunzyksR?w~_9b7&5s|4p#x+agGb*&jlG>ObHaw6zu)N2EGZK z^Y5dULmJYra|%}2FviaR>F22Zqykh)&vRUIlS_U?{h>;?W0+O~`qPg2iV z4?9WRW-ELL;q(!9D;nxx?u|LtoAd%8&VR0bx7wIF*r>`YGDskepu>@OastXpB8o^#7-tK5pKQ(< znw#R=y{?|~Ml|rxiTWZNAbWr+nuBT86{?|}8Rl=!OYD~1?j4(A0d?q9C@ocM1+fIw0`<%nC2`L~|Vc?4;5tCToqV_g; z#01oknZL|2D`ZHid*v8i(IRQ{=%A10&M;t6BLatJIa~n?DlQr%p%|Ub0=MWMgvxl9 zr*iODX1a2{3MwfGZ4)lWSZ)|<*ajE~2u0wI@4}%KHvmV&_pr8Z?Y7OfW6B}gx?S3- z+`LsBI^DK80Sq^LA7=OGBMc}5)DHlr$WZm-tTFkJfOGA6g3(;a_w+ah<~P;;cF5ysbDTz{=oPZ~zcRz-$ijJ1L($D8(Iv zJW;B&(H@qS(g;b|B%!m7HS3H&V#pIo{9b$*CPbY787{)VdQip}JsSa2UHufa)9gNR zDMc)> zkp+`~$;HXwKV|MDLH4IVrf-^ve}!{a)#PMd>_0zVUzc+PHv9EiXW%Y8&0Nr4PA*u^ zWo?b6a%><&#^SPoMcu98EjsL9)N$u7B4BD2Z3~cRkdZ$6{vhw=$R+n9d->m7|DwLboAd|GWq~XdT6;Qp?aQS=&75qNOiuk1 zEZHipP-!jYQRWFIHgMd19x&^~s9^TzGwn}hEA4PWr*N-#HP>z*(X7r-S)T4+6)RoI zcMPgxPGrfImXdTqOpLX9!x$H4P1v>%byt{HZ#BtF6{cgrYf4d*O2VUz0tzMUK*;6M zji-K?AiEci$$-MR+(`~x^*PSSj_SRb!+0#3e*ya`VQiVk?H;7utE7JJMD-PW);`G@ zbrh%!b!y5gQ~jKNAzfL1=Su)dFWs7Ay+L-OogvYlTLoTP^U86|N=i*rM(vbq)N<97 zD^|H2%hIZsOw~4Z>^-)lU8CU9#igCA3($<2yGeahnO2(c`7CV5q=RcjUWJ`?uCd3% znrRB(x}!LFZa#MG>EoOU2nY<9?H2KCaI?Cr;hjl&(o9`{F7(%v!}bo~9*j z>)HBa8wd4E%VUVE-Iih$qIyjdC}faRHmsudFI8YvCJaBP8rvNrAj(GCgsj>~P3OJL zrd+4ao@MH*^@0P)EC~0iv;ta|2Or%x5P~{^3e3r#{-Lf{q4u8GH596FkZ|HD@Lx;D zM&|q#gy@i&YtSU4^DU_*Tuar<9>M3;M7r4qt-fjKxu#IZ*A@VJsFNQBxHs zq&+nZLsF7~0ph+mkq|iC;2~1^SS5PEqwbNLs7YGR@o4s@L z;&Vv^_itiY=-|5W8h(WAr7%gN6J7?UbSnJ+SM3s^Al%tc|EV{6Q~_ z3l3vjz_`e9%&6@<)4Z5h=Av=a`32|c#`7t=QcYUTR-Z&Sq|pR(QL6lZ0vPd9GyoxL zbU`b8#!_^#5z8xa0<%VoTZjdXlZcx={3eE&_KRaseH2YGNNgs|>k%0LC0NJhi9${+cmbToNk3Sz#opc^LfdSL?~*rDGMDkRhM06}f|mVuZ&^ z8i&$nikL44`zZU6fycB4p*()=Ryq#_3ew~C7A#P=1W77$9<3u6lm}K9@6iD4?v~dh zz)D>AJZq{*LSDTG?+`4cd%XFib5X4^;s<~(a#=O0vqWs*iJN9|s+zGgbJm^P3F~@x z^dZw*u`xk1YHjK-b22XTDV0AuIs`e!JuR_5wGOaL0Q&-t>hryVoTM?o3Y~l-rPz8d ziQ>!v8#>ttwKsI3KzC^X6N>Iqr4lx@U3{d{(Y$5eyqKUa(b8q9fO-QCH3;v;p(fAG zU`Un|=Y_l6SmveMp=*9^x-~aQMHsRq3QWG8I?g*SET6n*#c z4C21N(1mxcbM_TVB&GX1*PKmoEyR&Ho|pRj!Nx;j}!>EI;^rTT|Id=DEM-+kx#>Q7W;owqbxd#*YF#q;~~m{7DNHL+a5e zA{vZeqF&0_Cw$EM%z8NEZd}(kMxwv)$?tnEy3d5oP+Oy9Qyu+CaHzw&1nTl0-Z1k`GY*Wfr(L@o<)DxBuZxUoXQ%( z*fwYOV)~yRr>giKO&$_1>N3HAs7Iq_MiIv~u}5$gH<~#9)6U5tRiBFd2N2Xqsl~Y= z51W@A6h=&m?oMqq>ppzDIx2nQxoYLDy*JJnc84{XsoYE%0=AsI4n|YhBBOGDOO}k~ zJ?E{>eKh^N)$}AL~Uz1)VO=1gp)DWn?c8JE561ilf260g8UBUTkK3xWqet6Atcn zO1-eSKT2u%n%8$a`^~UPuMno;7U^56xY>t2tJWl7hkeX&cClnq>j3om5hVGtR9QXo z!Fh%If2t=##WeQ7&;FTJrJ;4GBXIG%32yP_a9e37$E2nOKl%5rF9xpo=D>f@_oB%& zm}{Z+SilNm{VFc#)zN{aEW;9MILpo&Jp2X0%uoSzm?Igg`@X2!Y~6N=hm+6`Qf1US zPyO={84z++Y0obQr=e5{P7^3WZMsZp*RTznH}GQn^8+!d`Nt-FgMFy#UE~YoxZnKi z#oF@ESI8x7lzl{U>;fRe6`3UpW9W`LT1y;3d5!RQU#T@}4t$S3v<+`Njfa}WdzK1k z3B8~Vv&N4=;)<*eqBoJB+_ly81>cHO(0z$~h@O>1`wWI2%bd;`);wn|m*!pb z6!Bv)oHWBdeb(8b+Z(8JDtmISzT6ck^uEAxQ@fx{N-xMjA~osun0&lfQ$VRp!=*t= zi)C4wrBEwLF$=|6Yf|(4y89$V>--@Ttc+TDh|gmN8Vpw*jM)<;NBjG=?BW z{hf0V+Lm~wxoZ?rMNvo>iZZ3o68-}dD&GAN?yvE6|KdSazZH&J2x!sSxI1aMy56*Y zdp~GC`hlPk^v8dvAg7Fn)nPJ>q3k}T72z4D_trum6%G>)fmIf`u?TZ8E>646_I=XT zsXQ-l8@jCc<_6A>s9k)ebuDdQEAk-vzH5T?#lZNgGfh?9uH#V-xmy+q{;PB=?8H&$ zUSAyeH>H9@6oj&q!&7PS=mc$RoL4LE!wSS|fwR%DB5~Te0Ea6lIq7L374rtIv+*&D zg5cX7MbeC3CUqOUUCQ*OB9G;LG&|CQS$`wcB^H)-*Ak}p>oEYc*Do@A0YWh$ecN=J z98Euv)RP79hm! zik@^FGR2UdLagy-zY^>;N7LCi+w)xG6ORt*gJ#8gmpNMkEqW})2(#a40P>2A3J#v5 z$VaC`p6gm(=UbK228%@_xw+%=EZ5%dpT#8R1D4!kWSNZ=Tei}3d$m>$0!07Xm2%(P zB$^V+#=kN@;K26ps-y6C9Og(%G=}pKj9&d~?;Bv_g$gZ&EHeSRy0%uCA(xz$kP@yyCdF1Mp4_N@DK0f zf2SiB|6+Kz`Gy`R_TmWazKqMi&s*hEU;0YUK#a~4nEsR)=#tp0d%&z4Oo`@DbqR08 z`klq0&N8j|^d|;JlZ;oWDpuscqC{mnDbI}|;&DZ^q@-s{aoK3nyeDQZSU%Zb2b+u;7JPBPgDd`@EC&RB!>D%>+s@5lE#5+kBK)idf}+>q6~G z;~9x!cu`SU>P;Hx*=bxECvKJAxqu6|`qoRP4$n7C5gF9ojvA78ymi!w>~MmLZvw$e zQ=B5HGCps`TQa+b!ihcjEvFgMDP1p7!W5RUC+wjwu?i!DO6T$hy@7flP>Blp0UFyZ zhbgU?ZAX4(mH;I?(aAmh;T$b+YDL}r&aK^*nCZA>;c}UFCu-xa`l*D-MmNqsW$~q6 z^%cQN*NyfZL{bph=C#E=X?D1CC|Iya2x52D^r@;}H3nX2#LmR;HYUDB6LRv7w}}EN zIVU(ex|S$LcL8#ZY!$fVC{8svgkRId?(BtutG}QgUV`Ec{rmgJLV0+W>`9BzXfCldT3C%QV?BSN@^@dP0%VsSjs2uND5@xNK zX!^uSG_ZOg+w6HGqwylmw&igIt zvm`(NsF;_vG{O1@_#953=ewyTQM75wArreaX3L>mPSK~}4amjrT>C^*?o2sr)MT

`q~#ubKi6Yo(ZQe6g(iimi@LDhq;mOzvXOS5Mi(TU7}6 zL41BccNAKBuyOsvgv{Hf6PdBH9{#eSx+i{4ui&8KkL2v1@(%Xhiua!h5@M5cOK)oJ z%MYP}c1soJu7g5iHXEG@6D4}_zrH1V>5KS|?bbtFn^pe`M;39fCumwt#=yv-4pUc& z%=6BUBPw=|EPN09ulmyaY0`fbsBllg1C(M^MJ=TL4A;evIY>y@^l^Noa<2;-HJ%6S zhYL$)(6@jX5!O2z+Iel6e5OU0h0-K><)hdT8Q!lp&%6lmd$fGMHyL?-xX*R>Q{v*H z@VR4dt{u2yjkJ1GhTKwkUe6F)+izHk0r=)~-%oLu`)5`+h<;=GGGH}VK)u%ZjKe>5TJ0`xBx9 z?Q|ImZf@`zScaXlC)-hM%dGg$RzRw<1@Q#N~Jno)gw%nov#( zNJ0jIkykDX`qcE@mh9IvnmVu3$c91IE_CRjQj#!?2oaBb<}9$O!Qv* z{^o0kndn^twOGO$ajL23+f|(xceYtbLYbtPNOl&x)bQ<79HIp4dfZ*{0^<^6GNHRL=a6bzP01x2H<>2oDvq9ao2t~8CZrFl}{y9GB@RQ$_@xQA_co(QW#1jtxL zKP!{k-T4h~@#lLlq7dG%ArbRr);pDi&q5;N>3IuP>H!)Dx5FObh9O&;`_{2F6z_P4 zZmm5wTqs&cF-~YD4pn#E#AMNbF=KIo`E&YWW+q4!7g-gum9RtZDdmWs3y1DVI2^QQ z9i;a&!cHXxtZ12y@{RJnsXL%`$q}3+rUl}SINZTE8j)ho)``Yab3X7r5i*xx-dWi; z9!O<}LiUaxp7nHT4H*+@K>-`rxXw?;`>xuhrLgrR)Qs=-n^dp6Vv{3J@Ds`1dquK! zcH6Og-GiX3*H50npB(Pi%Y;z=E-lpK%pt4- zem-hazSr#+k6b*jCRpSs$hF&>*DekpQGyk8VP#rp0H+xp80aCgJF}10<<-HrWe3i& zR83#&WnK8g=LXur;6IlxT*CL9YNzy4hzywzYwNSlX}sD98uL5n_1oXYo0mZ~SLDE7 z4_-9CE=ygJbx5Q3`3b}bJ6u~STgFZEn^v;ja zV<1DAg|s1|E^ZVybHul-Xac*FiY_lhRP74TrkR{$jj(8QC`1tlsVGfD>%{ReFI6w8#*xt~@?Sd{E7z@310% z7j~OA0rh6)GL+GosLzj|>0DczMRT>T7$>vYE0UCFj8A|OWKgJo4W8@f8eT_gDb*C| zr4Coy^9y1**s;j2C;iU-)5}KEq%rTUy@{sftHzaw)Mm^_KV}fD2TEXIXg)5H&9QD< zZ#Pkb?lBn}1S-}s@r_d@K4E*SWHs>tNvuKgHmy%GWjTAv0eKnx0+*7Mv28u& z6(qq7brCp`E*iy*V6RQ)F5r)AqKH9ZbwX}E>X&k|0(9}_fTo`4eLW`DtH!&NL~o*W z&jDIwdOD<)InJ}3JLSuso2q$I!;{9VN}_h!W9E*a4dQu^F$)92bw9xe=rv8&)K>mf zJP|EP0S~xA>u=3Jn9oo)gv#pD#Z?gORYz2$F1Czf3MsV*5Toaaz-0Af_K6~#zvtOO zlF!p2?!(uLG;jTiJZtjjq1r#l$5XY&(f!IUoW=4*z};W^7hkh9`)PjDNlHQ!;G!xB z;#8aVnOFr54@J8x1E3rB{8EABU45J?BG`@!W|Mm$`>-eMOK#C;?=PN?MBZ<(h_B7+ zAoOy)**f~kX=noBq#+@tG>FH=Z*Y+DOnMF^j#HBiGRd3tF&76pL z6jFjzrB%55o}lIwRrz5oYPM!Uzd3~y8#v&n{}@CNrR;;Q z@cc@{GYd|z4SV)_$Q)XoEuFcgHhHLx(3L544b+QyX+t~PAh*1flsiH3`Q1D|7^sQL zGZK&_IRNfk!5ObN$!io&e{875%<;ZlxxA;<9->?s0;;w29yG!3^XfTq9HvY)N>hWH-GL2AA-MP@!W!C4RZH=Zt4pZ$ zt9O5)TB7#w)+s0^P{>qj%Sz4$IYuIaC>+*ow2Zr>ToLQF#Qi82UjioPtlZr?%aHXegr5P!cKc~X zHw{!&b17|qHFZX*>LG%Co~r7Z<%cK z*$Kf6kH1zrXe1$WLNbea;|PjvzwBu#?XR2^bcYr$%+R*CN9^4qV=AiGyK>%xRe;-MRyAAP-bhBHtcnzs9nJ@^J$-yzmdpI= zY!8k{8sBGlPFyXbjc-XaSO45W=CUp<*fDQ0WW2kn;kWD>B_`>E}%g(4f zFrzwIpsb0yQZ#~T8>EQl&Ny*EtO~0vAu)Rsa~)OEACRMas_#?DreK!Ppa**^#obo> z)ix$dtx*T1``WktRnk<@$n&dLZ`kaHRoZ7=8lYc}-Hz0HQd$d2g^aP+nNimczRs!V zI?-BU-vib=b->gM@z(xs+&j!1@b58;T0Q6>2w#dLR1oBaD3n0{YkZ>Js<=! zto7P_+UJwATH~cs%&xWgd%GkK^W6lh6J8HFtd%# z98oZ1RLgPiI`OyXm*Lp8QUMHco$|C_KYBfPf8y)PE(jfCeS<`~Ukf20 zaxA$Fyc7gIf!1|h6bZ`Q&L$)Ag62(4620Pva&!2B!Ui|d*T!P91a618H{$J9iV{*$ zSD)`Ek;`AV{r$B@;6j}oyl{t@K@octILA(iQF6`>21kjy8=S4AssU?foe={xF#*!#HSO0h z)Jx$Na&^*rIaF9IP@%Kj0hiZi96UTcU#qWH3wemsP^Rt$cYF|$za=7e&uR1E#(6=& zi2hXfPfY#5DCLijf?cjapek7JWjk`+*HIUaub~K}BxIGGV!?ybVXD4FR9{@G{>Phh z>;o^nzMvt47z(>+cqc1{0vhj;$&x`8%qShYPijXp1|I(AX=@Q6&c(qwN4?*ky@qx! z5xt^1mVAiT#Xe|Rum9Y>w%Y|MTtm>0AF7Xa_#nwL7U?2%Tj!K z2ROKJ3!kDBpE2T6_27#pADIH(%KPPYM9jT%jeq5`jR5z#_Fepbiw~BQw+(RZ=!Q`X zv+e>=Y65{J`z zDKRBnaICNC?>d{MnluSJ3}gaec=ojyDU=TIZNOks%h}7dus=j_?~t4MTeASe!21+Q3=eO_V$^=)#PI>qhUj+^QRu?6(gst z1wsIo#7}A&;M5Ukq2HGfH~+Z$i#s5Tvf?-%0#dL!1CA>Ul5C0!Yj(%DDG-@MXQ z?5plE?rvxI;25HKc1S2mX0F6u3X}ee?9lvx7Sek1cG9w<4bvfmh>FZ*PI3^e|&n=~sLC zu^E#lbnYCyhC0~&!*LYwRUnq*G*?-p9Ixi0UMCVoF8sNcb#mC$}nwyC_GYZK;gIR8@0Mz0cB;B`|=n6JKF-?=rSnREYGaB-9MwJES1{W0~IoyeuUYCtk>2oWayGp>)_50jw9#YWBdL5gMxsg3F3*EFHR<(`%N_L*mex_1<@S-J3O z_$H=1+XdOmlD4vMf|{q+4e2+z3gntE(CKXr2ZF=5Z;~g#`kvgI;oRfIXMa`H`tC{4 zY}7=SXp+tkJ&U)!k7wx6!&2sbiDqbdrS`=3d~IHwio!Ccpt38ZV2CG{Vw2rGjdN}OOc#?aeZ@&yK;YJ&6rIS+WQ=UuEi#ogH2SQKa4Ko86k#lYhXDfk)~(y}D$o;uc>Y zSKcTlmnDWTOHUD8wi3A;N3ZnP9z95br=Hd@R?ps(;<$La`oUB_&Fkhzicl~gCaT2= z#p(Sy^ag5znugh_3lS}t){A>7B+wAP`H}sSEXeuHE%w25Y$=|Id&Z#~4ZGFQ7iE;h z=KA{KP@Ux=c2S++#P{fubR3@Ft*Nn@D_U^mi$ur$7wzK3YjXVQi@)hU^E} zgkJ7KxApwIQf63^9Q2I>$2r(Lv2#_#MU}TJUSa-|CHf!C1tdK-T;NZps`|$;|4YV7 zQAAZjNkUH6W=aNrfDn;?m#0kME)*8foRgwf;H+#2nn0jsXD6fW`i#E4hvqwi?G(tK zq`lv$<8`R0GT9C2Idn8jX%7&vVJ@5vYC0h#G~3tv^BOliTVwbXBk_f54q*05Yzmgm zogs{@7%>SIav`(&w(OP2IIzbWR`!NQ5NF_)uq;_5>-o>R+ghmvgwuR@*+GDS?taiC z|1Hy|EGI1Iqa+hIPmkFBto9Esek~vEhk~i{ED*>g&1B*kOy)wu@XVdsuQ^z6nq8s< z8nKMMb^G4S&h+X>Ge8T(5sy=Z=MO4y4!8|Sh4G5W4mdO3Xd~T-6g@m{&`5mrIQn2< zQ0a|zgL?l&(8h`*%+dnzAkYa92S?2~MOdp~TxHR?j8V z_<;{TiNk!r&Nppb98}8d(1G-p??T!--P+Wcs%Uw4;gt$^TG{Po({`L}VmL1&AqtYw zen&AVb_L@e$|)J)S`_5C2+NH#hYs+OVB{6yL1v3ONny%dM|h6~=a zm4~4YL?~2B2=(;0Vs>pevjTgNe331nB{u{?n!~x2UY8J|s8E=|!9dZZn)};aTfzDp zns;fnq$_y(uLbYlk!uud5QDu6Q7fxg_I2z7o*yMom-r!t+2r>>0CAn24Ofx6w4s06 zoiecz@4fw`f1Lsw9W0>^ZDJ9MiKW11B$34y4PJ70UeCaiO^^o^)77y>wqz8e+1pe} zU?rXZ3CZJAPJThz;0#gf13&j96KCXp#c8tmEX9cMk*-E{g7zPQKR<|dN`6=Q1cwo{ zc8bMgTK0D`%Gonlpdg%QxAWuw>mNnD%kY6$S}~ubn=3=gnz>6pB<$QVL!VK_rIJF10xGtBWo996IvVQn8beBA$nNhYi}s+ zow;6tQO4M$n5709a-CMcY1KV&3y$d~9()reN2GL5xt4$ba<>971dz&{WZU&m(PXeNA_R}eW zkK!{ne<#=f4!cfGB{l(65?^%K6u#-bio6g|KgK^w%WmTY(uN=MS(lS$m)jLf^QmX~ zQ-rai4@HU^N?f-Wv`}_`Gk$c!7LE}3yq7&&8(yU^$p!K~Z+~mONaR25doTkI*exq< zna!0ZnjF$A71*IreH0&+)qa9V2YWgIb2pS-kn&`a1pAMekw(1qAhSrpxFJip89xtp z?MMW6s6}e<@;z*~u?(|L@Tz)&KkvRrY3VIJZU|^-Hfu^=r3CKgjG5?*2*YSU=2Rjf zT;jTZdBU;St<0XBg5~=!>w)lFf{`X5y$@KPqRug49SF-@@S@jXL;;;gtLKZwpKj7K z+-`+lS6MkOF*CbNOprE&Ei-}Su@%O?5~z%qsAF)KK1f^8Q>yGKvR{?{$`J%6Zj|^H zgWdBvYW^#)6<#wuUP3`z*SUC?kDiv_FUl@6U&T(IOPd^gC)t%r_wz~nTlnB?pREM3 zg$DGMdd{wIIrmNbIr~MQUvyqSb)MT>y;Y&%k;wxtU%!hLcdYP<; za4j)K8PWiOh$Fzxz?giAn+3Wwnkl1n;FwOQBYKqqtg2lgMmdoXE@03DIbWYXuaHu% zHTgBj?Mnuzv_0$8tPOqyDmP_fjU zA-s%aOI?Mr>A4 z->;^QHl3Ko9C8s@>QBJXzef$dP{AoOkw+!GQQ+(SFkv$-8Q>v|;t3PS-6*>v_Jo-L zK~PLr>w-0U)!4lA?FDMmcGuOtPQIQUZqBNizGTzKkj+69f8yL!dF3)tuG|Ti0}x%! zp;$A;K(WCT;OG51o{#UZPVvY3=DgdSF7&V^JSeJ>5i-xy4ZbF_HY+n;{%yI%ac^&Y zSRTBNo!(CP9w(nTEuCGpJ#lRYRY9cDz;XV14Ms~q8c(pU_GQHU;RIGi#gFTAk~xys z_jL*yQ7mJDs#_$wHN&JK3?Yt&48Lu~hn0}PRFDa!vBr*5^;ae4%hoR*%l@4)sI$nh z`QbiDwbsbo)`pbK*b(%oYxZ zFy&qXxt}6=>yJa=?8nK)%Nwt0TXWid;NsWjwYKf$Gsm%}Q#&yHz6rX3mbnVeRrloT zdxf%szmr|awIDCNct#SvMNz3;Qbz2T2%bJpqw+q(vH6rFhi1DC3;D(3%T>zukP(Yh@fr(#uXTNP)=PQ|uu+qP4&ZQHhu9ox32#TA7%V*Fs+>tUsZ%7BVb_CDo|Oihu3+kD^zdYn)|Idh1lLY&DK6K z{Wn_n7eF+{M+HvRoArIIHGs@TjQC?_VfTNUJ&GH~$Hl1Y!p!7E+BX zG)eyvIyz7kXXME>xbF&ImHq1k(^CBmuHg041%-HTDM1vrej&4iF;9B#e#MaD#yfY> z#o(gBC)=a5a(ei>z8LJLUnbWGfc=k;s7{xNoY>+-)9jmJCb9&H4WE$8jB>Ur<9~u; zp(DuyjhU1eDLG3NfJQljfl7prF($Y`5&?7Hr3R-c;Ncb9d_`tSYZWbG9Zt}P2`X!B zfl8EEh7klBBoQR7wo`+8^!fJj%_P0@)W>M$LU%#Kv@Z&6KaU{%xBg1nd*mjkM1QM7 zUR#b;0Ux&_rLI6NW84k)$l%7r@8$V%ZHDD-^dGxb(KKyl2O8{_{UaiXwOrW0^T6CeuUVkC=Sa| z#2(VXYGv`bzdPhI??wx$=;bxH`NW9q^mvL!BYjti70~uTE$fhQjwS!;E}WAG^aPM( z%N=HpJ32REQsxS$p)UhbMG}qxUI{{^4JMEP_2(y_S*k#eXRrAzxFkr zmAfJq8^wwkMyw9vUYW>|F>t)d;PH~k80>Y`f~Oxi-?kfk%Q6L!*=I_FoR1GD5XTxA zpe8>}`HejSsb{j?5dBIVIbLK#BfUZdf*c)t8jpee_K|hC%#%?n0*i`s_PGI%@;sB` zkZ5uT&!mX#g3O5%pW!N=a*~X1cA2YS46I8kfrzEH5)2p|H?`*u*=yiHyTyAV`eN)OT5yez&_FBcPzs^j$zaASDe6*;o zr#qmpJj(E0y}GaGr6l05<$r)Rx+{E-x>xvk-X#CbJc3oax7tM0F(09d!asOgx!V_5 z7hxqHe!=l%ir*&o)hb|-xB2_`!QYQRz_mCKjal8&=*AnPQ%ht~CT>sYhQCYxs##l~ zC-_|sj=(tZ*bqe^kEbd^mF`2SZh@?<;odYsr_-!t##LJQH94fx#Ucd_QEUO<1Jh+z zKF~#9jl%#z5lbCm@&v^s{W;9m)oc1T{%l?mnQT<=Eu{d)&rc8ymf3^hyNH!py;Yjj zw{$;jcL+b#03+c_;qfVJ5x76bJp-D~G5_EGc8NN%;ZFX-j+^0ChkbFo_v0(9T+-|X zt%oN^KKg10J$%07U1%D$r&Z~jkW#nF8?;#Dl-Kj$_j!&PsJ`Qef3B7g`BXTwr>k`L zZa4lg$|>!no2HY%V2yyZ&U_|!&k$|sH>4}->OpZ?04uxSxcI>9eat)9jG#zl`z6Wg ztYbs%2nl%7Z zb@tHR6P;fIBfK%dV#RvF*K)V)zxlk<1*~>) z?WZsPmPhPeVR(0xYo$(A*Y-Q6Dhl{n*l+p|+_eDVK_KF1#$?tE(L_>issjI5n?F`Q z(qrH|CzH~0G1Lm`An#1G-P`XKCxy|#?uB13CJ>T(Zf<^bjZMNYV+anTp_Td78|*3j z8EMuX%*~Z&iP#twmQlQGTu4VU;N=E4EE0C;h4E!2 z>kv5)Cznl{)g}UUX^L|%Y8evNjdeO%PDKa-&`hCh$q5A_TuDsXJ-uiRSfx@){7A#@ z#==1BIrigW;@gsSo4>8T@3Q+E3692j2%TFPfeYuGTYz=I#ui}X?D|QaY?~2O(g_~y zPj(wefz#K^fS@AH|*$m?Muq_lS0+fAZfWeRu6L2M0pv!vG zXO`9L3x}`<`)-jm1Lb6Ik=-cvKT)eKRL~Cf=Rq|{pAG=|{xHhl{{n98;KeB3ul=D^ zh~=}ULi|bV)d|Ehv(jRVYLwpbf@k`A=ta|rb258PAF@SZ6IK>}6~>Vld0BlU1`swt zapKi}l=S6qKEO7y+Cz$PIKf-;dHAv`u#^^zK8 z^}}i~iVWPrC|GAS>=6$VhH%zIDr8H!?o@2ysX0dR1!{LX_G7iqY@i*zcIlLP+H{&9wWbCF*|q}}O^w60$*2Cf0|rd`|587n#7 z(hxFIuzbUGbTorlY{i_s0S57N-h7jY1TC4TgajIA!j?qoe?A&5;VLR9Q+y~2IwbhF z0o)k4fy84HlDjEnZc%u|J-lFurKGuwMs8w|YzuC#U zp~z@%QLXi#ad9--U4o^fJg0o8+-~`1+3ip2Cv-LDT@Kr6VG>uF%F&9&@v=}YZ;j{q zFl=6Qfoy+8hONt>X1M9!UsSGUJ`L?!YPZvy@a-&yZh8J>A6i?1u zv~EKxVPvGza1G@VTTkwM)NgMuT$ed=Apu!KZv`~|O7qUj_3*^1p~zcS2t0;7-VwY7 z)N;bG&3*3gmBRe^a*Ni#%C*t4ru-9eGN;j`$s)5Twll>knP%O5KePY|SWz0Ih!PnhQg0#TMbGztyT+b~jhAf`6etxCMp~B$_VdF~%;-K&D{rx{ISu*pV(( zfuL2KAKPl#qsBf%q%55uh-WOppPp$$lfD$BwTQ3d<5S?nD})iS5IVF|bHeIAIKu`H zMaeV-X|@zuEE*qpBt--a@YFsmhBaIUy)=D zO_WZ-;P90|`#rYuiXrQ%*(pfoxX?hv|0s|#)svk>Xnx)}X=fN6vJxv$3Ov2oxRCoJ zxqqqpg+LD>N6b>?($=)ak;~HVrDVbV^dl}g-v}5O9`63MiU3AT+f3Lumpw*e`}u#J#N9rJm#j7S60q=CLQN4{!jP*|0{xA*5BS{}Y&d$Rbbe zz_Iq|#2w3@<#gAn1O^L1m8>Ap#hN7aMBl>wgMOSo2A}Tz;K;z8@R1zcfWF6X8jJrZ z(kz$M&WQaR<2XTf@el+Wbu?y#5Cq{{0@(r@0v6qpj{&XMU+nw()V^ZglI;O8Ir9i6Tfol?Kj1&H*VZcKR1%k(@FeP5Pe80pXdVxps;x38w%-#9x{lzVA zHpR%eB)enoym}_&6zSj+4OylVIDoMECYUOw(>K1nK;Lac>0FokGSED=gbWs~ zUK`haT(koKKn@st={9NpDXjiCT{gmmAw!fmEm!uw6kM=c~Pm7rZ5+<7J zDlbwhbY6gI6I$@tpa|^;@qL_%h$K>!>{DiOpbsYg)hYW4hv_fg3QK6=(8^n#h+NfZ zY3lYORFHm)S8YYeUzPbe1<|v6A?AOYSG@RPh0>ipC8XXC1Pn9W03c?g@W)K`M+iHN z)yqTM@EDFw?=oNbSs83*Bz|1o#^O`;^Wp|K>I~~Ez5`t}xTDMF6fb{6dEGTnQB0?0 zcFh$K?LoQ9FN=jRI(-Zyf9dr>=E4;#qMu@V7{CO#zaH#NT`^@_aYCi9#`=tj^GX)l zePV{ekhv&mT<;DeIzAYz04WKB{v^Goi|e8lvTf>+(fpcaTj3M1uQq8gA$@>!=jYCe z0hX|O1TT`hQAV8@_DZK4F=L1)2Vv#)n=3YqJHahV+q~c;X53^Z+nkCHwXD<(cjvob zy&Ww>CN43MOP(}fm8%GU1l~D2?s_vOCZ>fMq4{E6D$`HLir*#4)5pvSbVDw)Hj`zR zDQ5Rkv)jFosvm>(0nNPy!26fE5X3z@lOwo43s%$FFItFqfOp*n#`OA-6hVVEro@qt zHG9EK#{_KPSZCA2$;06xT*fg@?1Y(`RsAB8Qm%_9aH6FrcK(Oz0P|C)NR~z+xrQl` z#}hKI{RByPMukqW)rfw8T~1B#7@YE#B6DGzjl9>2u_XJt($Ij?3r{jwNfwl11y90#BGP3z7jKo>-b3NJD8Yk+k*NRb_z~swNZUN6H5&mkEjy2LH0DU z9I?{LQUqjC62hBAjROVRjQ03kNreUiS;f(rUL!;ytL7p(`BFz>MQI`9x%l8u>OV@Z zeh&)=ofkTQ`vu4LW)_lHOgeH4PVVtEBv=3+Bx>~21z5KyWc4aj8Y=j$fI?wi4?~6G zOXLdHPyX$#+3y#*b4)J(SJ$H~^9I5?Ko(W+lEXYSV~%ZGyVNgk{?_kT2${=9Sco&M zpM=OgIs&%}-A)b!#)TU}5T-09C){_g%CR%^0;>Ha94$4FO7!cJWR-K$jY9NFL}y=R zM3=L|-xOm+xPhyDcWG=c$~r>r=7f;@s^Ms3ma>O22Xvy)i7MCJ=#&6%6YGbSO|#}o zM^vIsxvq|@cJbq$m$yrBh098ndnG^B5HzBiJ6Dv%Mp@Vr*jE+Wt4?MZN}NVMa8ydw zE%Tofi=Md7%40umi`iOedR9ueOMH}$NFk;efyOj2skUYimu(11sKh%ch);1x`5m5TYO?SEqpi&=*tuMV zo*`CljO0p(mz%>wl4tA-M@V;zcRHZIFCE=8Nb$~?%7WK?M&=@~ZaU0Pp~S23te|BT zw0aCXnYDeeuv(hKJojQu6a>Q@{JcaHaD90jUtVLpc$)Ov`CiH>&XRmW!Z+{k$3YBg z6&vSrw}J8F=Z6+?HB4SRbK6zbDfiX>vHw-6DY3kcEi7Qv!%M~pr9VS^M?hY z{p8sDk)&~8+I;c^dYy~Bjmu`!2_`-pv47Iw*yPK#4%=T{T(#^`3H*DaVI{P99mCih z87jy(1~*_xl1){Cv8<4!hZbU%mLgqg1tTG^Ht08(I9R0!GRAx|Ilc;)pX_Fw8iHhZ zzaP5b=EiuGKvhlu7DBE)_2J`Hmxtu2*?VtBIqGU}4cvUm;Ew2Q_eT!yKgi~*^<%hN z64zx#1jQ}70oxvHNcd5Lm;@o27xjyD)w&@@tGoU zC2?!=lqE7o?CN67rJ;5zBO2_RntFP47+0C*+p$TRE{%S*xS6i_4RBtCUt0ubi{l%_ zOEg1K-zZHfCbChpibU?P8XDmV!hv$s7Oc3EGi)CM>y5U2xkZkF-Et#Oy}IO~Gwp)~AV6uM%ii z2DcYAX+xzp)u!a{xB1-JxY=h{xNv2wckzF|_z^GD(a~gL?cJi%8yAGYZ%mmGbG~lG zL_D&n3!Dpk?>?SpuePip+f?>^MDrgp$5g4zSj39k5vL8VWJlIS@SOWB8hpGPXT)C| zKEI1pKI)vG)=DeI+Vk5V!nMw;JyduHGqmN9PT)G+L&lc2%Pn{iy{isXT*{-a=f9bk zix?y<^K=vRLuA@&jZl%6_n79!yFc352Z{rGp!c|Uh0&dl(Ht$t1Z^Zzt+bKj@2WwZ zvy_?yZTdSjwyl5WeD(5&mi=3;6Jrj!rY40$y_4cCNEA_?{FVX}lrXE!mtJnFl0cmI z6Qqk*MqVx!A5FpiGU*8QKE(ytdzS@(6NlED-_dHO)ivWHIKsolfcGdj)qm9u(}7!9 z`~8RKX;PS#W$GqAK*~UsXlU$qK$lySnyk#pYVJ)g$36yXx8eaa=sY9;NY(MOPoO2#cH+ ze7jA(A;o=WtE&2>Fi5obHrDNJxa+)nNoLCf&P>O({w+Yqqw2m5w5EtGH18-*#oc|- zzvIOP5aaSK0uruB=bN|!UFf`X$@5}78I;DmC}cbX)KanW>&rwnnI1(*+q=%wMRO?W z#oi*$XXi87=*ElQT^(%+q+gaD9GrtlTwX`$bdDWR!5UxjVnOJF>}! zMUa9DiG!SlsHI;@ ze~v(3n7lv^R^e`RFD7kb?rB?q_F==^z_5j%v#uy7xi6U@tq3pRLt?^~rL6?g(Qcj{dv6|J3r>YTePvCQX6^ zt!f6uUruMQW!#s|u5n%zMqBm!G?kI+3X~|VD5%q&!nD>rDFlGri}(pVOa}5|+g5V4 zcI`RJ5s4Do0D!NCrKq$~#Hg)xJB`puT3K{U>Qa$P(G{g0M$c!(kmfgR$ooXu4vi36 zcItSRSq*vL`?a@ab2h(+0_ezl5q@47p`S7VJalbfN7@O~W(Ch1>6Hm9EG{!^$Of~5 zMQ#^2pJ$^yzz6f4X$FksmP%*$b30TZ+y&;9*r77VRV8sdg0$0|QU zJrG6|hc@?N*Z&&;&vxY16edQxl0bpzw82WZO}ULz6eX^ob2QV}wG17Z8_1BFGLo9{ z+C_R8R>^<2gn+~EI5Ik)xB|XgWC|ECY?9`NIr;dzcUlX_eq7Aq|7x(F4}rn~Kg|%8T0tV7tlc z=iv>F%c32kya=^pUu_O3Hyg(k(>!g{!B9m`De%aa=#w^_YdKqyi#NE${$#2VdS3^7 zVVjMI0u${aZn`mcA|>apGg1Am$_pyev6W(s%4;@UIG(-=N#~JBrc{4s`)aps>eMpUDA#pe@a?fWD0De{Alv69yIv#aVj`FwN-?XOK%+wLW}r0=Yu z7aAGI=vYynr7hXNas}s|AoMJ$#)fX~_6bj|_MFaCM8?$tc#n>`B*5wu9JW1q1Q6Lu zQdR;E&@)g>6#!_OWH$5pJ!`t%{4@R8SSucI(OBT}c&{(lsd&|FnVZTzY2%?Vuk_XE z2l=wf24=#knrVtmc1xoBxvZPA(7SIQF+c3G`^jvs{5pZmvaX!e&}OcUavwA`E&4jb zfe^8q(CH(FMyQ(5gQN{U1_v7yj2rg=k`hW=@8hYqaL)XA{=OJ}kW+uEdGA>8yWVKc zx_`>-1vfXU|Jd>%;yC>FOZ|m)1B=3>;TiLt2dQ;20{)2Zms+ubn38k-B=oCqZ-^;~ zKcfV40ij;TrCL53ct6NgRsK8y(d`rY?dgb++rE#*6e1VzzI|{B(v;E_Hqwt9`GZ}C z)XQ@tkaj=tlzpg@K%&)b>XXWxUpCmAm%2)d3(noKcTBxP>Ou8SViV)RH@3bj;K(T# zi!&Rxu<(~N2)V>qMw5pdY8d+qmQ>E4L;r_Ba6}IwszpbpU#96*drn4Ii#gj+03zj?7SqnU1p=f`kCN+fq`GA7llA zgYE3{TF{Bf;_?;(A+0!V5aziHpw}gjp#>+2m_&SZK8W@KN_4_K3#2aMrzOnCbcZ4Y ziz#zu&>UT!W1P}pJ#1#}++XZ6JlvXn6mWzX_KoxUfJ6jt$C(cc{%i=AhJISd=nw*< z@OMKpw>0DNq-|v&A_vY%e;v|LpK0 zExV^4?$*^fPM=}0urx)ZUgtg8>H#VDl27!&KcBBqZY6RoQDhbF+=pq7qtIbX6DHH& ztkDec@LZvkW|%<+NpLoyrL(mpeL<3zNM5i1y(Ktge@~?tN88zwg*zhE5OO*4kWytm zT&#RrzLVe<3|8NLAL4S}@f1v*4zc3!h zk?Axw*6B=O$CO2!4{#(PP4=Wl^GhbA8JZ$9opqwwYm|MW!3;9|p#7QpoQ?9pdZP(J zmffC_9sO=dCl(j7vh=$hIq$kuSZNhbZ>4erLd7b z(SNIoa!bd@6A8U85l$br9(=M$iUnpHoO^_~Wytv_&LQQV?(S2!lM?pOl2mXPW8L=A zl@fpR;ZTwEo|Jtmiru_9;qdv-0icYa-^x z8V5zfXTIBDF@5_FWZZoslg(emz(%+(WzW2WV4(*$P_vfPsHaD%kwtiPdelRX>28(b z5Y9K_d|$bLwP}_j;$D<(Gu8rL9y%~Fe|C71(U7mP4^;md@p)t53Vjor-{@;~M>Go* zLQ1xK$*5*81zZ5UW?$|BjFXKruwOK zUFFW;qA%wfRYH zAY#A7m_yMGBRPPMI7`J9-;CS;cM6fWmPXCZP5PUBaIER ze5>QAk6@==kHdc=b&WQIY0H`zrqPy61OtZeKKkOvketM8R#S{;N9nAvji0#wl)RZj za%&3*Wm@*a;Phcddl~PxvrhYw2z;tO@@jU0++ONsV)MWGbC$9zb!nv4$!N3L>PJst z^-`?`DGV$1U;!KB<~O7UJu^O!yWAucc;o^bV)ZOM#H$t;y!2-)``ZjsY&TcxtJ2!7 zT|BApCU585N^Q^4x^X`WDUNVI-TS_Xk>+WkdJD2f#%eJ|_H()SS-ku`t=HBRp{v(3kS_ z6;|QC0~cExT?-}euRD2USZtj_>u{#;2DMdrYyX=xK=5X@eA~=*Q32D!xp)uGZ3W3N4RV; z%?x%7ucNR{S6uakZB?jwb=jE0zyTJ3eb1`|`adI2!ZgW-N@3wXu1%{)8M|%ar=tex zu(}`Mtfq)EP{QtlX14nvm z3&Uo03%f-Df-=r$ihBFYT^$aDQNNSv>y4Ry zYQbO}FIU%C4m&e;YhdXJQ8cdOrS+W2xlAcZu|eX3#c64TbZBIOy*#GdfCI&TpOlrm zOHpp9k_)XOHpN|kVfL1IbM|O+_SXAMlFvq7)OP~7llZuEPH16$L72D}M0GY!uq;lEJhbSc}6HvOHrqExFY#-l=+N?)MG(rDP#4&%t2VX_DUtMlYZ6bB#Oon zsK5~OJpL9>SNvmAO|O2p&n22eqvDrknSjz2R{zW^TLOl}6cKD{@OxfB{=bucR7D+# zPKWi2o*U!)(xvviN#m-O>$}>=oXP=2<-RJG)SfX;2vanfBBQEPA1HX~fBk!_OY*$iIp&eLp{SuK|WC*n1V=O3`Cd}c3|#EpX1eQ4}fTnPMBQZ%7Xb_P%qyCJw2iDa}4Tt~a~c{;U8 zHmIy5fNYT=kOHVLQJ}^A2p^t#GrgcZL<8nx^qH`p?2zD$JtFugX$Yh5%jCramX6cj z?d}j<$p~!(f1p%Qul(-X_u%UpBj5o%T|_^9TXA`Q2u9p{o@?PxcUW3lve;X5A5i~y6Mybc8Cf$|q#P(Z%F^YvL8pE0vjB?Z5|{!6&*X7<746+O?s zk|DfSVLHn7&BM$5@|{U%W6kNTI7^GNWzB_vU^0%7C*J}K%{%dE! zOxZkVg9!7ks(%GUu~i_uNulFcU5`&UjoH^SF8G{54g&K^)6SU+g_B z8K^Ygcd8dV-DWw>U>kk*AhE4R)!KDCH$bvJK570}$?&!PTJTAnjatrW1R_B{?4_Ji zeqFknv)&-}*yal{piD7dzI5|syV3E}-Bq&b53g8VERmTf#SmDtLIj_fKDD;GF02=o z;7C`*ZbK3^JVucYB-W6R14a7yCXzLgXz@G46xMF+Fm@E>p5uG&^ zNjpS~5zOWHmS9tbWU(~qw0HT1T#1Ym7zYf%{$(}4OwoFhGl!vynjmc_n>U$Hzwl3|Oni1pEay5ZHm zpG;O6b4F`rhdY_|wpdzyO?v`%m8wOT(FZWP;^kks(wp zi&CxCt?hNoQX1sr?S~qO1{#=CM5$r0&k1kUm0tI8g(>PQgnCvAceCZEIOS;qhk(Ua zHb>&7kNJ-Gu4lIL^ooyb&*LWgPnXkqCi^+5!uVanU_D&k4t;hW==e=ErRxXRw&BdU zP8nXY6ho0a;vqYJd+ROZq9eP5t3D%FMPGq6&4;uf&*GYE{M-!1XjvYt)i%C-HU&A^ zE3WM{jR9FwHdQw%rrT;R5Eb`)w5_t=f04g_IT{huL^g1z(AKEZ#?w7&gy1si)s+A( zz^=UmC`aEJ^bH;F=X%n@VsK_`h)AM0z{P>(zxTnR`5A9tlrY{2k??>8B(tNA;gi6v zfCEy{6?W_TLY|VyCwV~z50h#tMmvA2z$Z4$2LCHW!;6fgc6Gt20IV&c540ifKPjpE zzYTHE3Q%C`W4$y!@b>o$hl?1?#ZqfibXgyc6B{i0Fm)alhmah?{!~MMV2AyaZXis* za?^8tX%n~IS7eWz-(5>;w)RB`1%}?We?@(T_7w*t22@hAM)8k~)A2`|m{nFaAnR2= zx_`?kvD{phc-B;>OddJ7Fl$HoEHD4chy>4|$t|KGXqng!=lB#Zs|=8pwmn6&Zzr&| z*n{>uF!mX=B&2V*L>s@!GHL9TYu-CY`H(zloP3W39O?l@)wBp}CbMPz5Ti8b7qVft zdoOMAd@JRvSGlixEa;=RyoEiGw3r$;DDPF9|7_d8wyqRy*#A->|&^kaKNikH!P8Ue=pI0=`Y#1S$Le8 zwdfxAxBj8P^i8La(TF;J51d}0cr+{BsI$&Sha8=Xl{wq}+=<|392G z1Hoj0`IX7`0+#>EWwrl*r_RXE*3`m`!OX?P$!S{0OBlEPzlz!S?~1sb`ly{yWF-cd zzV^9$duID07&8p7nAWw|a^8oL}YL%)Z zc03oZ1_7?7QPR8}$${h_z~y+l0)S~1Pd(>GlY@m&pO58IaNS{j2wQ!SlFT0-mR09C zPWm|WddO%d-tX=0HS5cIqa@1pa>{l@H5XsgXYpCu)ZO|o_4XKET_)um$N(_%l4((> zXYyKRbdTbcDvix5i% zovPyvW{+F`=rSn}?0-Yg z6fse4Sz-dZ=hm)Ln8q%p1BBVGQ0GcZ{3&g0Jg4D}hUcMZF~pDECl2FIq35ZRdjv&n zw(B5n(0HbaMEOD>Zs(@5g6j9)4FA-Fek-70Mqd2jX zn?Wa_7~)$M)SlORre~Y(BS9q?S;P)S%l(Oy`(qiq5x|Y9gthloGY*R{w9u3}oz*TU z#96$1^ayXVE@Uu2l||0G#;hG@?DHo-mQbrD-2*GZ^u);h3R<=6Nh9Q{E&zP*Jc&=c zG7!F}t}KghvKI1v(#%8PmXH~*nbTM>dMNhl5;+`0b)ZvjcYF#f1xIoA5t`8|h&93tZ)1(pA#rf zn>Zv*OuU7tjK9vfqYf_lWZ zSEysgc))g{CY3PB2as#orw!s2nGRSXVp2Cu@HSFvd z)eL*%tNPL)5&X~a(p0G2!}r*CSE_drB$d)4l#z6;#qajzO3cxW1EMH(Rpu32I7BO~ z{aBa^=0t!qchbG9H!n}w$xAr4iR-6#YeRRps{41gdX{$5J^f+OLtUcekJi*r%1oqGCj@h5%Sd*8L7GY> zC>oP6ACuWxHC6&LuSEI0bS#(uJSXWqSEzO- z-;{~UdN-!4?uzBJhlH{3gKVSsvvkNq!KegsxK@tQ)3<+J zwXfPzpU)qc7(XwqJ9Xcg9EKa7!{$xZwNDx-KUomsUp$L}pu}(W6Tyg(6koyZ!o%hQ0k`uK6-AZq&MF@N(ZMS%smxo4`)8L$Wo{JqjBwqCtT}S#>~nvhXimM9ATpH?tk6wAHN8c zx;z`W#qedqhD;K3s8grUYMzW%7rNe*HNWibwjmS~oy%tpjeI_^Lu)cAO-Ds;uKAtfzaLi%O&C6mh+hDvIb~rxtvm>%Cx)hsmg{ z)i5Ez$QUg_;f5h)VfuPClUdPu5mni^=({d#9OFUU(BNsMXi74?-?pK)Q zSAdbH>&%HSZY6)vi~c9XSzbx6!{G+zMSOs{BaT@=jV=~v*$5*D0Y8=;K^xI#2o42p zF>{on!Q#``ovrF;Nrcm*d`91XVE-Zu@S7^r10AJN7Y>d^U_ox+M}z9{ ze#!~6KO$YoF{yW^OEEB;E@84F&$12efnt^{sq@oH0X5(cf5V2W3R|Ry46CLc=FOgt`=DRW2Y5^IAn>}%J0BIQGA)nkz$b4*-DojkVqug_Mc#K zkyYoBmR=25uP(h_uqn=B7laFkHxmSrFyKUgYEagKG!x{(`1My#{ts(6GV5qJi_Rt< zEvE7sTs^28Ot3T?!+){OM+FGIcx>&r8M^jge{4CDqdmSC)!hf_yq?v`YLio151og! zq*QZT)2)-Y@bZrb=qsH5(K7Sx@j}ZE-G7CT;Zue|F-k(t*zZ38~mEHL9V zM^A3Fyv$BYuNL=rHcCgY2KOaPeKxoOoZlKV)iS#lz5mhi4&58RB%C5P{tGTWt5c=N zFGNYsg&Fi=R+`haqrQ@S{8%|$MIHF)e2`duqrY=qvQx9>vs$zLE4{E)ycjt6OHaBd zWzrN)XPciw!!6(sKZ*;O3G;9}q2gOOvrL5O1RJjb_nWF<IM66usfY_Aa0%oo88^7Lg()Z5Lp&Cly}5)!BT*aD{^^YjRol!Ju#ZUfC#pjGhZi~MfbtBSln#vYOKhzw z5OkCK(%bxLiF2o0c1g2|NKK|?Nw(KfukqCO*`r(eHA^i=c9b4{Wg@rIgflFcjblSS zGNshTyv1i;|DxH_q%vW)!gm?2f{u|6PI7U#csi8`@4DF-RLkTYs0&l+(+^k9Kr_^} z6K$B>LMCfPys&~-HM8yAWU(W$+pUXo;{p+vs;Z@3TTK;8Ro+sht5s{HzUg&Cw!JOX zb;YTBA-~`4g}uF9JhbVDvYnYCLVK{8Iqc$%)_-)Rs0U1`EyOD3KrL-XmP{^0N55Dj z*V+WA+fT|g2mGajX^Vo$N()5uH+ujLOW`80?^S|7`4ekor13j1Jx=|XdJ`_l;yaY2 z5thACtS0^PnBuKEhM!6MaD_HWu?GvX^+B4pZ~NzK9Nr{0hmZS&o%jm>%?R3N`uDNt_vQEA-I*RM zf4qZ?)!g$@KlVZF2`<`Y22h3C4EA8VK5w&>W!2G?0A8sxoO*PRNL#B=HbC4P;ka!L zV!S>wiv#?pB|}ha=_;3*<;Tz<|8w^#cD5)k=u)43mnNISIIV>XX)}~h^F5&*O5=;Q z(4JORM1W`w?86N@mC4y|sOvsuGY&{A`5-eMHnTPU^8kgaLpa6XLGaCtmnh1yyqV*+xF|F z%_wqfV%-{r=K1l#Wlt=Lkk{M(W zhT|n@9ZjwrcRG3ztqEZyX`OV-^*5C;1*`tLQnYR++?F-PhHo6}U*(IVFpdWr9Oqy6 z6UR)J(Wq2X>_<_Ghs>B|hxNeeL3gjvtd>4uEBgwl&y?t5L(O^&QZ+&HVHmKg?4kf! zY&j}Yj@Km0s<@MGm`Cjv5k%un*FCMhtyG&I4vOcO<)coAaM?4Gx3P(@lfxuO)2UG{ zRf{9brv(ds&mJe!X@suwR#U4z79`Q5gKqMB_o&m`-z)NDHEfML)BMZB6zkebz4S0O zhBqZ+SVC|OTW`ZdhA@BW2=c1b(`v)Ai9*ipI1qi$T<3xFd# z@NmnH70egqZ$1?28SV#|2f|nULo3nqkCD zw}R&9o|vN59~bS%t#mXw#%Xld3eDGOYn^4mfhp62)dn|Uc`M0@WqPe_Oi^5(C5nD6 zHlTu;R`S5d&||YZvroE<1~d&CTE7_(%G&a!{ja5~0RqOytgT?#bc~yk76Hv(@PJAgM4bs&GEtVGzf?)qHc+e5TlcXx@KRDqM5G)gzLRmZuK{DpevaeE8!S&>T$3jeDisi3|> zX1-Zo!y{#j@ifKz%MO>r?AAZg#joXTM1VLk>C`!u%7>bjTs$;X+9c# zpF-FmBoanNDsxfbksQG1MjuZBFb@pjJ6A$nx}wh92oyvbrFjFn{yiEd zZp8cU`r773b)%mDnv2Z+;8z$32`veu0I58xBwAoS=(?cWWS^-TgU8kC$@@)72Vv=k zUy4TE9Ww=I-e?+aY)uZCQ}c0^1{d2Dp5@QTzb&I5t>ZJH%(3(0k3}f%jH2^I^rYOi z5WA6rirPQ8w_H%7I8)k;c=AW22i8M>Be)TQZ*iqAQL~0mgU!!k8z=aJP$mp=S}FUH zD1JkG&?Nd#Xn3+*^Tb>%wA!VWo5y3GS(d7WGVV>3LLsL7yC9+h@yBG|Q-24eCOffg zaJEjYQM@VtN=3aF@w5s*R&e(0q??655w)b1H5yK=<9u4?17~6Q1^_ zgN^AikC+2(a$9nRDjP@AxS^;5Y9T;QN<2}v=O+`3Eut$7@klb&DJA(VWf=4PA|Wgm zD-KskmRR_YlvWrTW5{TvJe{aZ)QR6#9>x4eOXErLvM6m{Q9N&jqDBS+6(U86q*zfr zZB9`gu~D*dJR{SX;usbPM0wsEDM+lzCP7I`;hNpwk8EAb~3Hcnj7Datrd;SL9**^PgG! zi{slKDX_-ZiKIBY-?pXgd+K9iRz&9k!JY5oYTn>^k+R z1t<(uCsWh3-{oV#wA=f!!y~pXkjG>t*m{=B2YpD#%pX1SGkmtQf~`;0tGrxeuUGPz z_60BV$X}c`mXe2`;dhdU0oJHv8S<>M!a2*z#h_WCSoxdD%wm;tzh)pWnOBkJkq#Tx zVW&U-NSOQ^N>Rs-5{6x{DMuptdHqwR_~r^5aixOTeY=))#14IraCfg&QHr<%VmgL5 z1TT*`AShRkw|H|b9%x69YZvQ{W{33GQR}jI(oIuq6A4%32@~Tnoea00>&?#Lb}>N$ zk`9jM5ICm8KfMnyrm6HWH{=|AvY|SjVm$ut0yvo-xvZ8^A#YerF>PZe*}E*m5%O9i z^JInDf1EwOPGV8hKz%hLI6=Dx-tQz<9a!}RSh3lmbzxa2$IZd*>@o0f?*9yinacx_ zJPAPxj>kCBs=}hJXZS}vwdCoXp6ubk(aGs4 zBJ(QZ+W16K{;kuW+h@IZ2gj|`kG+HAv-T;%S=wJ8fk*YGIw20~5#(h+Apcp43xtTX zLO0~#7XOlND*-JucoO=ipBPly+aZvGkacTwduv`PN&oH9_I9DU?_giWQY$O;UXZ}n zp>^vKNf?McDF{hoBs+l=m}B2yz>*7sAb^3Wt}0%a`+_VHrS+S6=erJu3D1ZVK1cRN z3fI2EN-F_4jXKwq{G&-klEuN)sH7Fg*2M&&?K@o<=7qS?c@Wq?VfE?VT15-y&q|Jn z+qfs4Pge{j+wOPyaH4>6otyC*jvD}njs`!GX)ahBdvqwqFDdJ+;#l6-B zsw-AlDzcs3VsC-(=x(zSmfEyC$%92KT|pN83As3%avI4gzm9jE%Sw_t;wdM*wT101 zszNj7?^Qg-e7nY0BY>6)qWH)H<>7dIgPC3Ft&f9uM`+WF-Rn5ewH!toBp%jRN*hay zJpTq+oRV66<-ysmHS2T(Sz3qj!wRZ8a}82$k*1oY00>#2PhMFF zb$@sZOEiOAG9TCT_~X?V`XD#(A9}qhpTws9^*qnwHCl%WLtn5R?5$_zgr=%rhtzFm z0ib{@{BLRTaJnm4J!z)OwGN+sm13aifL1Bj9__tm z;ewRoPmRs3*H`%rNg)r0I@k|~UX4BQ!HRo0Sft%Ttk~6oXVUts{ua0ih1E)jXusyf zG#aLdjX@A-k0HXk$gfO>E9Vd?@JstNH@5+RBYg0pj;h`|T}lMi_T_ctPGHSZ-3dkR@&o(Lpd2cmXvzkAchXI3u^Y%s5#uV>X8WDXa_uelY2TGjO5IZ2 zJHpY@X6ZMeS^iXSTw$I=*{CYw3lh$sX>!gTO)+!JP7;2DG+MPew1Ah+$JXm@LjTYy zo~zn_=$v1YNUadbO&ckQj(DfGQ_@dE3D#FW*dq1PNr(t` z*xF~^G!m-uqTI;VlQ#Qit)35>AS)s~Dp`_!5zpRf^~lpx?Nvf3+X<9v8cJ28)VbM} z{E4E}cqu`rN1H(MO(a1r%0R7Dv55nbz12u&Kj`dSE}2caoEt8;tXe76h!qv!AS*)O zP+Kwr*gbL{hO@MuxOn zwBswE;g(C-&$Hf(N>N_2#xFdgMn|Qfb4cD2plFo9ccYOYXiOt9U_~SySOQv}Wn$|< z5H^+S`Iy)>8Cg+mJ&?`3Jovklj!=yuR2L)EP{Q&yiEvEqf<(cyBDvL2ySVPN8sk4+r{EXJrFqL547If3J2(LfcMKQM)b$q)Z# zj|G0Z!B7D#LQ9e55ej`#H)~-*tjN@B0GGk8j1vWcFv;L|q_IK~pq)sd}tz=%Qd4&|A*8hvu|0_~ev_&tE$xrB-HP=Jb4z668 zN#%@CC$#R--q!ZtnCZf4WFlmI{G>dm(&6a4Gk(T8He-~Sq@mIj8b*mrw`xdqcv+$3 zQ1VC|ngm{_qPo4_cxr$sKv+!gAl~kSF z2}jDR@JVOY)Szv?Li5n_DFy@or8L8sGNX8V)k1U6vG2{tldf#hKL4sy2}Ez>SBoM) z*~xpg<)mss<6#|%1`~%ChgfbJ2zKll{k|}Zm?*4X3za6CNalnylC7~=UoMxK28@j*ow(``U@`i*3x z4N)$aLj_T5?XGY{lF9I96;u+g|JUMh_D^^MW<{iH{=edzE+l?~!)7JXvJLKF{eNqN z?^bHG33*)d?`b%i{K@@auH!eCQk|rS zQS1>!c^N9qt_0qLINDp6_E{*zK&-y$6gZHx;;^yh$&ibA=fLOk*I8DvX@I30M4p`1 zXISExf&7rfP*3Za8-1cVDb1=FDS9(9JaHQuWRN|RlWPWVCLxdUwSBbJIGZDwtCn!k z3dy!*yo^BjtRps&Hm|m~f&7W*D{ti${Z<`qq06T?vQXw zj)b&v7O^kZCtrAQh1#+SSFjViXEV4;Yvb2Xzm~7~>jlz0;_IgzejCMqUFEK?mo{)P zX;I}<%$p;N&U_b^&O32|HYjiuQg}$0u&rcU1lP5t66)QUVOp`vRy5G>Err%$K>_+G zx{A*({|YamxErGkr!>S{-kKyYO8PS^Qs)nviSbIy`*cItKV}}Rt_I9&0l4yUQJ7i@VeH~gWOTgL} zLQ7s_Q4n&lWPd{M1hr0&dTl(%u;LAqC`4B`f}VM`s&_D`L)bwW<*2jQ?OnX@ti+PO z^D>GY-kn;tRZZi@(%V)q!y665ds?xMxp!fQe!D*DW8ztXit%W9i%8tpYu`v^=-#hD zVM%R9ICy^R*xycwlzoH>A5sAOh8;S2m}+2|J`LAiPf}G0!7&?P%3`kL!kW4v9|S%A zO7!$fK4or_^%Y}1v4A(e#|$;8*WB+QnAmjs9#pJpNWA6QxUI%YDs5SZ(py{n+ClYq zg1fmH<~S1#XX)|tX@|WY9pg$QM-tQ0L=x%(Zgx`(Bkhw~=DYMV-$fGB(nQjnGG&P( zQwjEW5O9zq`BpCne8Kmx{6>&R+AWlOf-*fR8{z#yDIku!lIB_>W>aI}N`oxnd|Hl6 zn^H<9gAKcB+F+FFtC36)jF9_*9XigP+L~uPQdyaKqOr-w`}8YW&V^jtfBDkT9R#LsI|5gsNDLV3(7-_HE0rUj<;z#)lHmSjIGe5)BZf{ zr9DiyE`>XTCp@kob%<9MG-LE&+kXe$=#9Py5fbrmx?~PTO8ppWj z5a4ct?@^ye9CG)J?@%Ldoa}$Z7DajL;|4M{pz#Hv?G=8-0KN}Aq`lXr6B3VGb3;c)K~9jaC@Lh-mf3WY_hsTu%X-K693 z3wv-CIz8l|o(Zj$O1$C+@EY-ptEP^JiwN(G$yLTnZI(bUNNj<41s|(D0td{Ls-dPmY31TO2&u6opU|SF=UZ z>LuE?O{O=HUb~8&5Y&SmK*{asl#&bk%XiEs-oWt&|Gb^1v>+X>4s$KsXrXORPHy@B zE8nj?>a3BwOrHikc3?=1qo>iJ$L?Z>(e&Rt%U0AFlHycNh>x#or9Zz3k{ClPwJ|oE z{1Ay&IKPm>d0l$kV01S>DJD{D{0pxBqFaf!O3G9U@7-N0J2m_3k+^p$tFLM-G`4X~ zB>qhJnk?k#JvizAPlw!$Ll&M3dnTfe@uGAbb_=k|7Fsq?bX)0Oj(J&E&^rZ4eocig z$>*ztAc!X%y>kDiL`|i-JS=JY>W5O{LPm&{xi2w|!u6t_hwZDc=$9uYBmERHUqgSU z@wFboeCGXoDlUeWj$^^|F1XF*iLW#aYr8_d91EgP%E27;oD!&#l8;=NmUyWpNpN#j zf~;_GuoA_sRVji+)^VK|5S>4e`;P9;)y922<)kVM_<~;hm_whD?L!No=%m*S@9fH# zpgGk3Uw`g&)N4+;X+Ni|4+Ug9{N^eugJY3rO@u(qIu?kc7(-sP4$#3P$$T!C)TXobr;^D zqYF_D=t8Qp`XDKudlq4p?yahQj94F`;oNkWR>UTzfX(V8 zd>C~xg(H;mw$j`$5{=DLJ$8_FU>P^X0p{d5mb|Xx;?pLdyE&Sea$H6ojJ=qUM<@qk zv8y_AfiEaHjKO07-oE8BRY656?3pJbt(BIzQAkTIM^hWPdOVu2y%|mD{;k!BrR;ZW z(S#2_#}Zy|R;rT6#FS6_o3SzH3oHa_^NUJ$ zzV7=%N+%cc-?!ok7LNB$<&CQ10`|^ns~aSQI=EDy-^E1df7;Fe)sB8ySFc*w)F*rT z8w(3>W5m{q;WQe%vBUc>S`d-~uGEw9s;T#7rukmZxyAhFx-h!ToYLXu_v=TnO=iX4=VO79F8 zrsH4w{Ucm5Q`&?3b>@|RKDqcQY{kxaIjQX!A6AIwJ-Zb4(tEn7_-CB(9pfag`Cy{l z5&ilLy=XEq+&jGVh-Jl3B^kIU76tmWuO*HK-MXOF+hSBmM_8x#K=FJ1=LgbT|+J{GC`S0AU9 z=NG_xG`)<@-l8JJ;uO(gq072s>)Lr#KN!~COp)bZUPyODII;QVve;;L&pUXAG%B{< zV?%WI3|9gt2S*eQ#fJ= zJ!kMV|2At^LM$d1qclf#zL4a;;UWxq-boWRlk?Z{8R@s8jV%;F!~;s+b!%jd@UtS3 zRmP1+8AZ=BCorB<+;{uka?DCzsLx`1O2uV0>flhoo4`WMDzAK2JWIkI-yS_dV*A{? zJ|o?Q5G7nbADlZWF$jg+$QGVRpDqv-!a`1RO{D+CBLk$P_EDfYQ+bV#3Ihl~U#AM= zvVaThk>2B)L^xXBXK#| zN&;nu?>Xg$NahD&V67iJ(shIhWI{m@@_l1<%#UkfgqJzDw)HP;SLJi8`qPg!fuEF? zW^4jz#@n?S4>QOLdYL&EXW#I3Og4hFDY95uklps*&*4|)rc(yq8CNuvwgx&W2AwW`*w{Tf&OMk8 z3)+rBFoJi;Y4iqH(eg)Zc%1b!3&+J!@r*XrS@L<5sJaF@zNV5Sv9;5niifKHNAe^+ z`uqdpIsGGl1}4GthT;lMBF-?SlOea~>SPwT@)4d|I>6Ha8qSoWd@;ls_tyEq}4r&|Ei>x}50XJy)9uYq2F0VH}Qwbcrr_!1}Gy;0}@EUJQ06WMH_TgdW1b?l!@oo z65TD2I^vHAo$4E0i?_9y7B)tlBt1!R0ct9a6g&NwB=Z6y5^({ZXy7F30+~0)d>1e} z>tQ1%I2MCnXUx7v$`lvC1?Ln*Ed3O*QizyS z#;Rd+Ux29V9`i)ht*5hjhup-RxA8XP8U#m2!Be4Auya*kZj7;W?Uyg%w!&CTe z#`JLP#DO$h7zt~>HGzy6lj#OO)G@@)E%(>xRR(oa!Y#v|oEeXulds<%_&j!TaBsnY z;xa-I8G5I6>==|nPferb*_4QL;ZeqtGo)-89x3@0Pt($P8~OgUSuWq=yoQI@OKjU1 zm2gC-4jJ%b7mAHk`+UX zzqlSki)Y0!gRCTrK~@YU@sf{5iD$(y(`SzWGno}{(CFPsyUA1I5toPt(C)*q4~2M+ zc~vqI7mCW)Dbh~hn!HL=>Y;<#2+lUwBBkv$kwpHMCXAKApg5v)!np?*aVfm=@`CIA4uiU0r_0001NZ)Y@PaBOvREio=JE-)`+Z*FF3XD)Mf zV#Qr~bK67||C@XY5snZ~ocM^HgmM)q(BYi63^1jDY_Dw*SrU@$*i1h>zxUoAI-R6t zAnjOh_Z@rhzPIOFZ+d5wAUeyI2XA?w#nC)itW!S^;>g?hVK5UgTTjw>od=QfvS}J5 z`6;M9&?mbzSS)kzz0Z!l{?*msgnozod(OWj{vGr01^-_1@6`!Q81#C*6Z-A*?|^@Y z{Cm#7BmN!p?*;!}^6wS>_IpN3zt8T0_eH9d_cWg8H-4(TFXDA1NjUKyN7K`TgFINN zEcaK*het%;?VWe~mq!N>^K2Pp-aH7Ehwpnq^=PE8}G~S ze)KXO#3^$s5UWf@Q{}~T&-YgTbV->NfX9l>){6zg&fw+e-qY{DeN>VJK~q2SmVPt? zG0_+?r=IsX_hzxmyeQ7SV3mZsT11E$k*OwRj{LAR54>Hx=1@{K3$i>7ChHtzxrac{ z;?!HkvtYi140s{uREl^YE-GDRNEkUd%r8}>Qa|*5SWm)W>U|STRg@{u&%A_uvZb1N z6Nn*())IN(sQ~!Y+o&|7N;c3z7 zNfTxvYU&P#Vw-hxBSxjuRi*Lh4-ClneQ*Um!&57#qgtGlkUnZHstE+kHx z00+vvYbg;XM#HDLG15d29SubN5Go&p=oe;4K|WoojB?`xiD_4ReWLU8BdQAP$%nJ#?DRm|4e_9QFh6%ES#J6hDa{}=m1v&EtM|dB+rT2oPcwhxN0GlYje$IG)a2~r zOl^XT&S@mAd4W@}nSHpc9nr z?x2J1)CRdn7>jh!6jQ49NgQRtB;?q^oy2J#P*<`HKuV=usUs9>;07{EEb*Lr$OG<& zQ`4DEkQfr2$J7i->Kda8CD@yz_gklgGW_st2#iY&D4n_xb*$P+P*vcd7qK5op}V4> z09JltG8I9jLA=iRE2)tVX%S#dfE*dCZTpx?Bv3(P>J=#lbsPk9=27i>1Eu!+vtNFA z)cyA1cRzmd@Uv$>K6&({`~44(o;-Z^_`5HEfBMVQXOF%`NO4N6S-hfppP`glOr&m* ze{&3!UFt1w5&QL{C*M8#rb+r^Zml;d4GM_6nl57=abs$Fx?Rm}N=!bk)Q5jC>EYYG zL+_hrb^DNWlBv+dc33_dh&){QY+?sK$1`{en`9 zcpP~AS0Z@$&Etnp4-P)t*I7kqD2U4UiP9b`^c&gx5Z7Ivc-`(&g^8#CY~O*jl0WBR z#C;CY=R{AcVwZJAOOIZYlOOt7PU3AARQNZ#A#}bbp8{KILY^ zIu2SErFs@{o0PsJ(C!-Hq(&inO`w^vHnsUxSH z1raqnX%vU70{CgB*nFTe4bedy+$^bs;qm6}x4iBm_j=v~bczQaH)rqdKEzNPC|ALk z+Swr}_l`{~kyhu*`Vhi+=zQ>iNL)Q6zDfy$7_ ziB{Q3aha-&Izb~NTL$y|fj3E&e{Gn-`^H<|kC~!T8$Fy)N<*^FPc>78x>JkMO1*E? z3={I({kJJ0hni9%+b0?9(+OjACLI!_qy0sYqF@p~BW({l(_+cJAJdsWUWU`tV(18{ z7=#UgB3X~U%KYiUEJkHGkRpGJi@bMSOvx(X9JAV#B*gpZ-NAuN35n|;v(!$BJC8AZ zA?B7nYvbq0kdCJ?ZczVrLyAFeM&t$T3LeI|lm6`cZ+{@uh-&lqPpRRUk>n|C<~iln zF=-25Q5(F0Zn4ht1`UPF$gxrb!6bw)P51zs`9%F5XCMBdvsMo%N7>nLzrJ_c`SrN_ z>wC|C>%Qo8=@;&|&wd@89sQwm)9_0>Le#r|MO)NjYJcl(7u~0GAR%cS%$&z8Pb#xuYH<1gtb9^VUBIoTh6KT}U=ib{TF7M3`iRA_1WgKp-aHpN_S=WeB zVWx=e0hC1caLwnfx4dsuew4Y&ZYGU%co@}1>zycS)iG-+fV7I9VO(P=xwJlDGE}x} zRUFc1YMSNTO1i^-ujk#w=`}{YpQvF8y9=HbMCt<8bAOscV@_|2!3kKQ>owT<%y4gDF#2E_ejW;m2(&O?)1U_-~q%T%{&0Df+S-gQ-7@?l3~oaVc2CbnU017Ay@?RjiVhm8c6YTVYnFf zdJGIT0Qq6=O9(MqRvfZ}Qt^B+Jbz&XtfK(s$*5o=-v|ae4~+@?W)iBOP*NER^Efm7 zC`Aml3ls5Znraz08GUushhr1Hz6O>-PW1;cOL^WO3^`6BaBJeqKIx2Q#VaW9lC}l? zqU=(iwT3(}(OLQ_`W2>$!vwWW!dfgtlvhZO1sP&2cCzA_GW7}rBl00J*_vQ_l+(Hu zY1h#@UrJ>BofO+NjVGc1x1tJxwu9et>wUX#ih2^R6;0T5G--DlT^n2$tXOP-;5m`k z0ex=Nls`cFb|5&349&N^OwDpG03OlJANTFkoaNiP)Y(h2kmFcopz;J5Mc4)D$WVi`wzBi&^wAbB$Ip zdZT|a>e0|Uy6n+-`O@#O^4jw+QK@b|%~P6Zta#1(y^V*@P(I<7ezT-M-fo3J zB>_?r?Zh^f~bSbF@LV)V`+nAa7`Y6(X^U)g_88pCOurigCPJ@k3XsYu*!u-1a1MY>2ryX zF!b@uWdhVC2Ubz%WF?iIH4-U*=d6>AbVfU8o#d)WQj2Dg`Bc6R zt|8MBI;|2=9y_>(WNzoGb7zyjS9aD((u@AJSM?~8<=f$v=Rk{!`n>^?FA(xid&k?r z)RVFw($Se=mFVO-+Bfo{({E3UGt2*prVk-@X9` z2FR?>W+;3&%2tf+<=DgT6oUbMdCF|pXTKb?YQ9kYjUJPJdvz71tVNi4D6QmB!s;xN z;2P+OS9XC^stAyzAxnkqHoEoS@)}e>$KBGlMo<@X3NL~aH zX{kKDpFv3tI?`G$$G?xseD}P)8JA3ngmMb|F(!YiX%35&m%k(($jPE6Eipncoi6@S zF0rZcIBHn4r)9PNuSf5jIa9dHf&Y4h#1|G6W?uiJcgZxA)eO$$yXpH?Wgi-Pw?o~6 z=;#7l-5k!Mo-SCeD#KCM)r%gZv35Cqy~NC-E$jr8wDh98Cd6s}CBBj$B5oPd6+n*x zN{B$Ah1A4An~vq#qyV+XZagQ7VNut`Qxtab%t*I2-fr4*I_xq2`Sj2H#g)JqFNDx4 z`0PzHh|xyC-7NKmhV_2&oed2TS^+BDW`S|chdt8ZnPz^$(GfcUfLH<=*vNNl>VTL9 zzN1-KaG7_#+2fLI#@iKW4iGe_XG zdL>|Ed{|IT92i>A#axV#qDz{RHAEcB*&gsKd(_C%K&YJC5tWP(c$M5$B5pFyQAeNm ztq|wYKxXQp^JpR)nPPMvjbvA4G8^@ZH3E-iPLMNM;BrO_9M)`cFx6dWx&YS3i}j5oO`TABv^}Gt zAvbSl(-?=TkIt}xLz^}N{i#2pd_ims7(hjf2hM_>Q+820oSR%F%Lh(t`!HdOu~UF- zY${%AGcQ{La`p=x)&wfT)WV%XWMD8@gau6AifvSqZkrm?J? zfKYX;BQ^ENSzB;hdke5OrySIGVCFz#bC#Et;ZqEp8D<Y=;6qMDjQD{sHm zdt|d*ly}+QYojZaCa&b-#eCl4#hcjRh21xZ?(lMqeIxbQ20&CS9MI|54tXw!R>Jj% zR>uM2x2t`VsRlBCj%HnYB8Peol(V{TzB^KF}mwyg=9`Mj!2 zpVlFVkeb}>qXbiFQ>AD>n8VPYZij(D6B2=AY3L!ztn32q0+PLw{a#1-0Mxm}vIABp zERRVuuF4n~8H2mZ7&sYWPJ{ALv^ulXv0HUB9jVzK{b`1-LBq`i)}uM6ExH)^Wz(>F zStND?>(DR;)5Z~UTpS^p$T0l5NRkGIQITPlLBC*1!by*bz4ktMnH0%TIrq@H`s+BB$$EPm3(+{9>nq-c zMnAG;r{HcY!Co<*SJ#88gzI6ST`ksdg?;#ZVAyZZm8V}*`BcbfhqLc=dwIepG&Eh=obpaG$Du!nWRF1UE; zBT?FqoE!)v&n=Gj@|qwsC~XK6-f#GSvvK-<#2Vr4ZeG3zOS(3{0++aVW+8{v{Vt- z!kLwS$LCyAoWOrUTy@(QZa#pi)RMR~rjMDgiRW|6l_twLYn?Q!6q6>m+qGu5Pf;?F z+u!wS8412KEV>plG27iC&Pg9Bq!0GIXz0>HSnzMILVRA*M&-tx z=^#hH*TRPVzIz#Qq>+QhU^8WGbN{zT#&mPh5Hviyz}34yeJXR+=`z%uR>n0Ba8~W= zc;!(Jw&sAVw#R=(4Q)^&Y#|ypjf>H8*pjhT8*93C1-yKYvlQUFi)~iqLw(v^jhm`4 zeCZUFtxrtq`klKm384urj+=A>bE8J=<|)fRNzrS(&_s?$20 zAu@sa&_50raBst zR;RjG!dV!Uw}4gOWQ3n<{u%Q?w1r|v_DkSThpjWVWieVJaAx8^dH_))_DWnMFX9zB#iiTtv_RYOlAPo+0mH&qgT&<q!Q7miJJT? z)LTuyZKK~78L*m%t^2pG^0^&v*ydcPE^dOZR3Y9Ly@!MGRi0TxEp@xVfvzpJXDVpP zePD!|Agl1`eMT)cLt_o?vLPdv^%W{hK59xayld@?_5wFi);bTjv-c+D%MgN9786|O zE|He6k+H(Ei@U7`4=l&J!Qv<1YCQ8ntL3N-6ibQ2RqL!pZ`RoQQ^N8ahOH zw(haYcB>V(9PMuHd#XDi^I=1`XioIC2A4PO0fT2N1MSei&sK91VDA>xGUyCTbAL=2 z%j}5T#t6Yx8BjX?w!KE%>#%9BQBJxEN|wL4*sN`qV450+WWHzoG(jY00Ky1)m+dlc zAm#hdhHcxecWc}Ct;_+^&1GMvOQ!_YIpNE*kM+aDI0w2<*t!dk~ZJX1!t!dk~ZR2X&Hm7adJ*V&I{nk45 zx2m!-ckGC@Dr0BF-|ME!i%DJ15~JD5C9dJ#PSHa*4r(}=urbd=G{t!`t`}Y0f(DiL zS;mQuJ=8G6bEn<)jrrRI?3JPmAHUU?AxN6Z)y=_G>!YH=O6PcnG@}~9?U07+H&pK% zlQRSv-5y)|K&LYAL*Hb7^Sd2t-RK$ReafvA(QJQNJC<3XK!sCvrtOa?DU0a9GUefG z<$iqLIh8)|GG8{LS)`qic$*|0x>U6TBFOs`Yb>^mOMRQoWyyQpo#hQ|OO)$Z(@}U+ zLW5YcRX7Ea_Df#y`Z1s$ z+LAJMx3KN77CXRbDxm|Z7O^XUC=`{^!^))^`!8$VO7c41v3cG<>ZC)@wd=JyJ`E=7 z+{WhgF<%O`8TqDNMzd7sFTV@k>Mx*dhv6_uPhGx-|1WMqXMx8FSzTqgnz5@UHFf9kf z_9~|kArmG-TAU`ANS_TzY<0X|#VO=@#`Sz`d4K-OwK>g3XGkEc$1kH^#|e_pA*IopMr;n07HvYap6%sffg&1f2(2^ z$&!1!h{}qsze|(Z24Vf}3Ik%<)-;Ej3Z(sYXx|>|17QYB)R5AkQtn%FngBl}>HFrB zGms6q)buF*RV6FZm70VEN2kGkDs*=8S-)XOFo+cXW=2a>q4rx4f}Olq#I{t&Vx>~m4I zRNxUJpC$NLN;^@ow3Shq9h8--@-{d^mwVS&w# zLN+2X4jDu(7ufdg%t^hq+1MCc(m(X+kku>VP3!srZg)f(FKm>CRtl2w3N*!?ia7yxZl za_C6WV&1nQpqrue%HRv{l2ti|oOado?qqwuq(Y8_aA2IG=fkY{# ze9g}za>I6&r(3HaGM62o3fKBj<<4b#+;2bRRL-08S9#9dL(DbqQSieUL`4~*Amdwf=3d&>XbP?sOB>WL`sT2 zBhefs3=~r%{0uq>&<`H&LeUkc?U}p z2iZ@G$#DjDNfyW?WBMC^-Lo}9JHywoIA?5Gc06}(zJebzoG8(HKf(%kMOSRW2?(8wkQ*qU9YtE-> z2})ZlspU2rvTuRpj>5xu;s~d>58ErE_yEH%}An;_$!0oG&)J09KGNLjvqZ}lcCz1J22HGue zR9o6_Y*p~n>vBm|1-O<$;$a&lbQT@7+pYIWkLzDBqziVFtV&F9Ry`pZLwxI{HE-Q$ zQu@#`?%c7VH3PoP=PcjDo;}Pba@x|72Gev_mPdhlrfnEexs-{i0FA%C(_A!RS)NqW z%kh_`Tl+5CzUp>}O)T3RGk-BM%)|W9Fl}%(ExiyqqDvY&)enDUgc{&NGGqB3xoa!XT zrJn=e_GZtX6u|P?kEUeD&umRiolQSiowuK2%%b7K*i4c4`5o;Hv+Me=y()+^QPb6R z)}HdG1IO&g1Cz-1@p^A=VHb|Gs=uVy^2SfaAI$i0$eI**jwlL98yaP+=XZZqTDY=G zyIHZzTi(+Qm{yd$p7S~Irto(_fF5E8={4c%EkDNZycmgE%kPYt8-1dj(@*rkl(9he{}wMjO- zIsls+yc>44cIB^D+47|mU=`lFCkj0R$`%KEf^r8ol~xhdDLbEEr=2s1n_&_>AKrQ9 zcaM5fzRwxjkql-etb~ag%N#L(eAXq+iW0Oxj+@kKn?-9Rqyeh8mwemXwtVYW#2|0K zWcN3M-ZML*DOB|`q#@65C>;dU>K3I8Ob_NAxPOtG!?rK> zTkv0$a(9wTiMg-TTH%YjkhX-t!7<2MPZd*?kywP#4F#lx9pS>8JkzE zhF8wcP8t&}wAMJ9fzuPEnqcw)^AS9yc!R zcyjX?XJlfeyLXnnQXM2@Y=H`1>}UG^d9p1vK*;YUUVPcPWsg^8s;f(w`jIv~S0H>n z|E6XxY7IV7zxMY^FECB(;*wRfHqv;Y%jo%dh(LhYl}<}a;V8(KMYHcxL2?u6!FXGd z`OwfY|4Qk~4k+DOa5`XLB>H83RoXxc@jy4ZGNCVu#W#$*M*tjGcx)A&pitg-4zW!t z&h83jQeo0|EH`@X)c0jr&48UNy0nk~4)}8BGv%eCAT>le6y3;`JE_Z9{n~N!uISma z(|8EyLlSjZI;_^x-~OGKif$T=J>J)Qlt}Ij!0|0~E)+G?=bjdSgx=#FFRNmZ0g>4l z4;@blj&NiUHBh!+Mw4CA2*nBA1vwWY(wOndDHK@ps>CB_hK52s)WS~@H|g>u%G9UC9uJ_!@nUo-#bH;L+MV98ervpr&ZEy z65e+T`c`FMB0->D+<_-Mticp#KVPy3BKZB26NR(iVfG2Ao`6{1=Aq_I`ExRl{QZqp zMH*{Kd-=SN&UTfX2oX@fYQ-vx1oDleu>Y4aN@A7L-o291Wdt?a-!H3#b|Mt}HlLiF zX+%=mM+!%Ki$H!6nu_NPyb7x5nsHC*7|luXzKV!vVL8LJVkZW^otLAT(9Ajek|@6-q-7*S zrG#sRQp7pXtA}>MDkD)`XdDZ2-ihfb<@>OX6UBV{SeYuV5HYz87WRRM4#-oE0JJG% zwxEMRL%<)<1`X&6R2517(!VQZ#iZ?b ztOBK%D$I-tCz*3C^{N(>eB1)Ar&Yk&PG`gy6FUTXlZ^t8V^y@YE6ed+l~CZ2D$I-N zl>X4ly%#HdHT0+(_$qQtMei%)S@Ujs3sAnlm^hoK{j)&OV8xNf)oYowp8y#_$-u!d zI29{IuPDJ@EtFSLYn62dw~J3-sFj%d3n@`GEv==tt7)y?V>lXQcI3>d*x0>Ik}^dY zl!!0K<*t)6y}fNVS-!d-=f?4ZFR<;?bww--wP#_gw0E8`SJe$`;R2m5Hy5aPE^v@u zDSuJm=){#>JRTw-VfL10lAZ^JONL%gC0aG*fHLHU>eCNMH!y;UkJZo|gHO`po}A<8 zm%UTl%1RJ)F0=#?!}x@H%XSQZqPj5h@h*FKD9gw&3+vGv(1`>M z?#S@T8xCZ$S*K|*%N_-}o~j{LF1{PODdw}Q0@IW?%A;(PN zUTs!LViUlC$9&Vm)A5!WDdwrk8i|NniSdJj+kI$}l~!dw93TF~wzk$=*1ZFd&Z8}Vm0E`@|W|iRo|rW2Vk3$tx^iMH5aQxYpYcO=|7+l zKH!$H1>)Obka7|s;m*5Vbbjqj>wfTjQP-MWG5cbCbz5^Yu;J?B81Z==dRE&>8=?d~ zrn2O=@O75wH)Y?-e%`ihde!@VtN_2KZVl%z|0JL44G|bpx(i6nJzWP`7viNaN3t(C z7g5Tv(u$ENdTI@3D2V1k;7)N6O+Nz80(w3pcq4%^pb)=t;pxTIu((?;YmV?zJA@Q*}@MNRr2zZ~h{jmn#)~N9HCa zc_VVp{4>V_Gspje%pTl+N{XXo?XX{yRg9hpwRZg*ynLS{+-0Hyv(N9#c#2X)(;FSV(LHFghpm^O&Itnc=pg1Aen{L#cc{s}EcMFbPpFOzHg_jh`0L z(muHzRN15|Dw6uTj&-q<4ifMWdphVH^9i!KL(VJ!8g*ju5Ay48G*nOp(~Pg`mE}#> zZ>Q9$^E1&p+_z!<2q**_=FBHgLn;7 zI~o7Q`7`4JL^yrNIGoaIGcEEN1e08(+wV=en=STp2f;_fE+lMl$9^(=IA7e}Zv)sJ z4t~g$M~rg!5!I;zGdX|H5or8viqZ;AzXmm-bes~gYZ1jf1dF|^Kn|D^63NPyYk6xw z_kZ;d7XRv7wpHU0+Yq@wAV)0@ip)rv$z)MUBRmY|Y&Rof+o|!V6Y(SVt7F@<_8uQK z8~+(TFjA9}BS)R@h7e~}EyjG!GPDg%z*Z%mQJ zmJ8T*Rr3_zu0_0{ zT8cQZiQg_x6O+g1v>DSX!MJraf;->DV$!>T^g{FARU`lhM=0mx`!+Lv6W;E{A`K%J z>18a^U777raC}#-6Sb;>#u=%yHpS!~!Ns#1;U1p7`OC%ccrV#RPYTVjX>rBYhmldq zBslP*M4mo;L2M9%d*!Ep1t=Qta06H^aCZ~_4Kmr;Ttiud%r8lQlJc3s{Ifaw{e(iw^2M`ffmv< z*x;7v(OVr3wS9y^PmlKwyt-?3I?IEGP~mPdBNz3D%4udy$(`jt;~J47ZN$(_UE(!o zL0D{(=WtamWL_xwmW$wbOU{BqXJ>`fUQm*Vnf}$UNN)n0FQGKQoExReNxk7m#RiZ4 z1;eQi`~}c9RhG>Cs9{^3@fj^G82CV^3$Z|Hyk}+vuW=@cUia4gj%taFudW!bTRM-h zWh8*K)qN04TJczV-rM^w@S`*G8|LzCKZFS--N zF@KJ6L{xg{tuYUrj*n4WmS}LWA)Kf!g93|3aIeV9meicRPQOB6j=x^!=&0JV^&?Ud zSbDPf*F6x?8}49}MHfUo!sAJlN%72#qa|ycv6j3{NO&&E>%*JEPvy9aJfvYqr=?$- zA!`mVeO}|zilRt=^=6tZt{+`gUHGZHENovL7_S9nrc8&`)Lco#^=`ghymTr&KO=s- zdANK&h7sg_J-TP98q+~$B!lvDTl#shXA}Enm%i`!6ZC#A=Jhg5b`+Vo&9e$(gn$kZ zBGt-R3nAAs%@qsMS|muUL<_{`%?A#F>DMqboY3ON!-OF-R}2%G9KQ z*NUTLzBYVUf7Ri&;Jv^n(M12VT{KKBU-I=D0N$Y5@ z7OzjRa}E&i)?yXHbDUdlMB@m_Oen|h*fEyfU`{}_PQ2Em8SWztiaL42-@1rLBWV-b zZDgo(g9qI>316)7C?1}&E*2R4$je;ASRt6m-o2*!?WWo_bvZNrtZ^=?F)uG>a%AR9 z!&cW9z0B;@R0ZUa#AS0%vCVo$<)f1qgX;Vatt>+wKk@Vh;2YRcRT5)XnPToUA3{5kmiZIyhz4(|lv`MT5Xi~`MDMdBK?l~q2Z^C57;dLx?ytSpMy|C7` zTO8D^=qlA~ZiEq5VR_+l_CZTiD@vHo46PW4r6~CNv1G;i3OGC=nb#b3l{WkCTFT1bO9_(v$>`ml-Fa zS8Z*Tw51WXpqV@o zP|`ke5qCaGY$Uk{8k(jkv^!zXazJui7%!Q0#coVOk0s5)p0G3NzvT?d&S`TB0gbLw zqCBfFs85Hd6c+!=s18RW4yQ8`8{#~&K=h#MBA3}dwbg9Dp6>bs-ZP)y1$Jk0i?LYf z`(_xL;A85Djp8&a^%W$cWO)ywgj$mr;iux)BYP<~pM)o=;avC1`7U^jpk zHgg7VIYkcL6eDm1>Zlxbe$uGXC{4sIKrEcXg;5FN9T8Dcx@Sp{bGWZax|Gq8*{Z&F z*x4l=T1-+o(6h3Awvd$^NHLX1HtU$XP_B+3=ele(8z$nJTE8i*XP9#CI>I$^jJ&zO zK%x-!obx%4iXfWV5&2rc?W{(5ZDCcKluj6Ic27NESH36+cg=}7Q>|2&DU z6YP3zemK+mNd_gSgSYr+U-C*!pX9}kavXY2I_aYU7O!>uwl}y)*+j*M1bn~NeVPYKoX}MoN~=va({dug&b?*Hf33nmg(1*!>gDtJZxGK|F*~6+Awr%Ri(aj zA%bsa?lj}dI#HB7#i9eJv5)y3>!2`29Y!I(*RLd%2a|D5q1Iw?Es%opRc3XAd0jBg zK^bt1G%&-Zg@T||Y`D72E-CBefltYVZY8*<00sw(M1xv+e>b1Z+;5Sa{*7(V_J6l^ zn$;$-m^WeAv2(@EGVq(Hra8ysMcdP(60dfDdTVk-k@fJHvh`(rjdbw_VT7vs=KIYq zyt7BoE^YbO?bI)8kkD}*yFA+|XQ~r8XnewgVFkGPx7NKc1Il#+!xSuSUH>5&m%{pZ zwae&Jf74?3WDe^ROe?dW6%?Kls&%`&suey&VvVZoo6$JU7PJqe@~h5-U9{hrZzVRi zW0;o$XO_6RC_q-$87|&yw-ZVf)P-%ObC! zGA#rg9jz)xx!+DaH-D#I^|1YXj8U0DgePa=Q9KI{5(+BSrIb90o!<8=`^JYg+djc; zQC0X(@C$g)Bpp$bWWHh${CNC1>1#0037|KGsfh~h=3 zm4spU73qSibF_m(;<@wRtI);o7bh2K(-OlaZ7?H1PVX}h&U(NEVS7b-n01@87ruFWMEqZd%K zCfS~WoGHkZ^~a)pDnOan*U7GhFx>O4>|wQ!9j=^}si@vMLV_ZWz2AL|(FXIs;e)v# z6z1@ajcn^(UqcQ}#vyX#iC#uMvXhqM^EzBz@@>Si=i%Q(ff-SRGzDRiZ`fR2x3RmE z=yjUGMQ97~r3O7JLt}B<^yp-bX2phMH1e_Q%fLrM$mJ)Qjkre0=gLRdapYQ>gO&I% z%&!&`bCelMh`y9OCWzv3$9PaCw8NS4my0=UP&I5!XVW>$zFm%&g{%z6s!landX097 zPSx&F`Ho=!yFxr&?8RF+@$q6RWUwKmf-K{E7qni06XCyVmb82{GH{E9*52`~V{u^? z+R1U7c26u-k%ORe$wrwV^nH>rKnFE#$}(xLUNfWtScq4HThWcL!beVs$nT6*k$Iwz zysx8P$6)?yH8KUL4^!g_znF}zD9F;GETrv`EY~jb#CbQLje}*$ba<_*vPTe$Xq>dz z#GXr%gcx=cx`b1AyS)DP<$Pf7L)U_ii5iK^1S`=8LH?7m>&3>_zu>gOQ8H{N#S$tK zsD#Xs>unB%gHv>CQey*2W^GB zW2Dm*L=$X}Ky!m3xozY)E$X-_TV}*7PM`Wjm9c~hS|iVy`BP=;n4Ip~amwzm z9RR8+EHO)@>wb5-poH3`Lq2MTN2)kVm2p?_4Yk?taiIbj>Tjgvs1cubqme2j+RVm6 z$X1_Zgqq-@d|i7}63=4Vg$+T6qEB*;g|4bo;MVlq0UBPo3(bC5sOUKWAxXMeoMWPg5Kr) zT5y9x0~57)H$la|;sq z8Q&5Vb9XD3g*FA)m5ha`m6s#*5R{gry`C}R29~!p7H;j+YXNh08EfvHwLI4bcmV3S zD*Ja&B^@pnNzPNpmf&kz0`ly#o=7of9gRN_fPFWMl%6xPv0+FFO5J)cai#ual=%0;dCP3akoJIq zX?-UCwNB=u#M}{Z))dC{^#gQ=*_;{0@8RA1Y^hl5zfQHqWH$Sm95j{Hlv=`Rdy5r7 zVpa|3hFa8DXZq?6IBDOZdJ+`Ja8wBw_+oL+I%#|E!F0c$CJV?*cbor%K3*`G2V}U& znc+X%Xr~pR8$MXZpsv#FdEUrZ2yMs|bNODT{#)N>mjBbFzfRwXAtz(SOlNrQw1{?6 zH~o~AFa{3J{~!J={u~Hj@ZOmcsADrq+q!Npn8H@D!bpnw{ArXw81Ezv9u`(lKHB9C z81ZDgvdG``+*h3Eb||>J?8}$HH>ME=R?A5idy~9z-@YY5yXe(k^%e9!a$zn797We^ zt*T9ZLt_%(xXE8}=h4mzm0qc*HN-I)`*&?}wOsIKg)#AreoiIF!KEg%I-J^%2_*N) zbHkN4EBvsgbRO?Cn|(191cIvLKbna6iBPja$Q3?A3;jn1XP&b9(&r2iY}w%j&I_0T z+W%%dn8DTi1BYYq(aLV^DR*D$%MaNE9tSYv(L}xNPFPclk!dT-gsiMePJbB799zGJ zb}&K9uhCOD`{MC)e@NxjXJQyj>(QUgjCSUF*SIs1+EHDyB-n|K-cKFBN;>}$fBU{Gj z=B)m;EY*FaT-tc#(*GH{VmW)YV=Mtm$nI&{QYCq$c2H>p7u4xbQVA@K&;QVL)q1y? z;g9Htf$rZzNkptS>8Stt!SIPYK}gU{b3Co{5l(dhaL+Uw*6RGlQHK+jY_NDU;qp6$ z_wjVmFa8hp^zVRn++|pfRcg+kc|B_I8`{1vmN;OjKK@|)Lt930P0o;c*lGOrHVAa# zaX0Jd_Z{cyK{pHJl& z1o>01`6f_)5eo$!w4|x%K`J??3l-Jhj)9 z)2e6i_i6Pye)oxUwk~DU$2GKK)@j!u+`<(7-3Fl~A2R17I78qCi}hoYAM)M{J#lCh z#6oD)>F3wX@qiKA=xaqu!4kds6PM~H{!owCJ$y)fP2BB~*5aa|S!Nf?I?hNo2VM@~ zB%eeOGBasvR4w*@i#oPQ_gEpkJDrNcpS{XnF{R3(WxQyIcLr;2&#*FceS4J^vTrTW54P{AH86fR+0ZVBwi^T z|2J1jd-0N&03FxKe+d0lH$R7m3wOZ?EBxVc6rKQ7$7k!QYm6#JQoH7*PhE>C$SZ@E zR;qK#zXX~|)u`UP4rbH43yl=$NjmF^kv|l8ram{*s{U{GYhsTH6?2Nczy@5#_E+a4 zVz)H2l0HXK6EsaoW6TZ(9Jg=y_}ke#|9Q&*@Mum(e21IX8Sw4@iw%i~692^p<7AQw zPGO=PzC|Gij#rU7@{y3&|2O%!NEU2BW)qQeIj+b(@a>5dToTy-qUWMo>4-oZds-E^ z(%uV5caqPqn^vv{jfmS7n2;@vMz+Gj*$IVHPPpmYHwSnbw47O|#c`Fc8t9BR#q5oK zz#A}F#TZ_arAM7hNnoYdpWf%6R+CLfCw@?e)F4$HlM9R@mBeYt*Nj;-9J(-mr1yD` zZd9_%*pBxWC+kU9u3vUQzpyfQ(?3ge>6Y2t8TVSWsXXu0YY80l!6a~3&+L3-Lco*$ zj`tLrc#lV_F+Ux}y`pDMz)QH}#MlvzsFIt?nWG||G&-VHgFeRe#{4Do3gcjc^0Es~ zF2*`aSILyb&yBF-7cuJ3YRS~SFj;63RW+S*FaG|v!v)bTx(APT*>yz8s(QU-`CA(z z6-!T^mFvUMRQ~O@&HL|K-pX>NSR_{xcwXOCvU%5FrAzV2Kb=>?ykW7>Ob|~1y(iqr zY*btBq}lG2K0-3#p%@h)uTYy7tD^gF+Wv47+ur%eRocimu_qe!;TftvCt0d>{@{wm zSM?F^jItY*^h|Klj(-DtyMig`VLgmkZb8?t_#$lsgbd15lzKHK@UM%qfz`1GQj6Ur?{x0VQ z5UlS)XGG~Au9hubv~#=2p$G_Cbb`8f?ez>4phzAvrDRIRCc~M(GM-LS5;xaX%~`P0 zL|wjs6r3RQ{cuCTz4!peJIS2nQkehq_0=bx4$|V_|>IE0lAFcbF7FhVFk5Tw|<#q7u>{f9V4wr+K%Q9i0G<>1d`{)39py{i1cx9grfGAJQhd}JuZna5n$YBB+uW9uTN@p&-A zbs7&=t>)bQHXsJW64E>A=gE__{isg})1`Xyah>v&Etz6Xc!F3c^8!h@CwbDv#}kE3 z<+0T`1wq)9wX3EMBQ4;rQEXYZ?=MHFu4R+COp*rgmVqZf3xO!=_n^rU5^HM^0ca%$ z7rid1WNu66cNd4aiUX0zh0=^Iqjt4Btq7DnZenihtFPXmNwXJ|&~a39tCY<~_$Bb4 z80GMnF{Hw?S+PtzrZw15RwbQN`Idc(FZ2c-MPF9i+W-mVwlT8xGDSR+4=Jp7`Y0@Q zPwF&S*FEvu+m6;FZV+uSMfjBlX$8mTV157QA<#E8QIphB{dOK7fdbr7{mH~wfkxjUur1&9j(4<6YfPdM-kQ!5`I3}AIAf80(_j)qZt<+_ z`R-_1-}vi?)}nCf3xsZ(lQE%JEScWf?qCvF;3 z5J{`rH3U}DI63R@2~p_fD66ouD@;H|_exUpLH`tXK=?UbYLZvaDSfZu{1Gcm<)li- zZ>n4rMVVE!3xW$1VjcsgOXN=neDr}MZC1$G5feH3vSSY*fQld&p-4nQVb}yB{bDnv zlSC3841N4=DQh`|^Kx`fB8~}m%6=Gn8yH6!8uv)s&f8H%w>DF!wECquGJo9!i2mOV zyFASgQ0-QuSI)%{Xgj2Qj*6*0pKFVEM}pLFyfi1`osq$YxH=|q3 z*mn&mAz`Sk73*&Rh-A5^Q79v4WsBnQumXey5_PRCiK=+p{%yrH*Ftt- z9!84F042hvsCf_!nI$t4D}cQ#!Bp|jVDh!Z={DPes_(2Ts*EJ8aJbZkjko3(j&u9qEsu@h%Bk*e_+2dsugw`LNUQN+Hw<0-GIr%PK4;f zd#@jyg9=wrb9kKa_yl)T-5Gd3eB=ub=Ztau+y*>=gEWE=a5{703e_C}Aqva7fL0(P zSv!M-cL!h91WnvXg2|+05fJ;8S|ilRjoBn|Dko@CL=QsrD4tJ?NTQ>G*>4fEY*lZI z>Od$QaxCpuot(d)eg>9+rRF-t%9fanMof?=auN%U$LE_YQf443I^_L((iVSJV*usf zEJ|xpdOWLEI0Ls)hOD(w>7`Mp@2iWsdz7W~ImCVAqP{S-Wp3VdeqaPd$!x4&o1Y7u zq%}@Wgk|#7eRQ9)kTW82T0PU8^9WUWa{!j?yT^wI6H(yiR!Oaj0EJEIv~!d`U|rp= zfhL?~5=0yFPgQoJu3954digz;`h!Z|6N*``C!1||hc2dKp!R|MtGl-K=PAC`C}^e$r}(1o0u5`3jtge%bxxV!y;h)*p2ake z{Dfjr)>$4`?MF`*^mD72vO1yto(vLt@(o_-f|hJ+2IHD~KKp(4?IKL+NgU|M6k@$g zkhlr9K`saAE?7=I3Ejm+brLOIxItm!X((335m*2x`zj`OQsbTS*{IpL+;rm*tpEKA zD;;h86oHgbVUYE5{-~;nL2Mwd|$mx=Px^M_RA)ODXC;eL^=i8eEs(M zi6lm@?yZg@IPq%VhfMw)DtPcrg>x}pzLVJ=uwz^-{ANZHeIK>eM zRTPl;7sSi^#1GC&47%#=FHH~wmvL|oO|Tipt<|LY*(^ORn3lHUQs+bq98OIOZfHqP zGpyb}Doo@de1J1Pd0~NL`Lc39O2s!Ci2N)HRvG~F^ zwzXOy6S3(b*P`;M4j~(}rv2H`O)`eU_N_6c?9bYq1X#Uf80Md-s#VRue>$ssP*Bx~ z7Xub9eQHMiR0`vrboluck{9SGskd4jVKFQ9k3$h|ucC2PVIXha9hd0h3^FAJDe@^0HNkNeimrCqh4f;0e0Nd{jZ) zkFZ;A&O5-AVe$WhbVudULu%N4h?O<=c&}cLmt<%cw8E+7Ah&v0c`3FdhuF^bwg1q` zB-?5xG*o!rOYHu_KD~;1cxn# zFI)9?%2*t$7WF2cRxGF*-f)EYc1sDB0k>V=Be#E0O%_W4V)ZI zF^vioUvavwFHzO(r!+Gcs687_#<1*!)?u?K-O~@zukw3Cr>lyqqu>SBx7zEM;nk?a zm#c60OGYTIlj`G@Hdn+Q(rirnjY(r4;;=q8A)vP9zsn3i8cZ*Wo>MT*ymly_K8xyT zym4khz;YE(jt(c(T(OT97=nhQ_0aFY+EN+L%SFetcvGgDa#GR2?+65zKbL&`9QwP^G-JrhB>!~ zL>5tLv07$HN#juJqX^y=ia4x~{NbX0t(C)d_H?WKj4&T&Sy43QGH!&fPlcYHIv`#pc#v}myf z{#~V-TPWOjB#RKdy#emj*{DP4N2LlCbTO)sh|KD=dlYPTtCi_3z8;?3k@T8f=SSA2 zv!U2rHCnku=XuyPLOlwP&d+^ACc`ioG&BgnrzC(M2uOd|*78TD8;}~+*4iO6AKYDm zj6h?We}53(oAQ3gn8+yoQ8WY3{Pz+(o-O<*nO3{e=inZP9*re)@a;?ugS}Vt`?D4# z)alcGGX1Wd(qIhZPpAJKDIBm5)cXGiR6wi0LU?{7;j&P1v0*}XyhxW};{NAk4;AX8 ztoc2(7{^|IKFB0@l-3+RbNSS+<{Ki z^GasPsw*<(_vM%g(xE)D-mER>UxB$N3w2rwO+5bYAN}-1EiBjXJ{nN%c*DWn2ZIkd z6nq>AJ`M!`kpscUVc_F1@IO8b6b1n|G+@j6t)sw)7zWfP@3hN+imE?2_q2>NXUlv; z*9^M~3-tX)1IGW|2!M!C?*FE8)>Lez-YAMU95Lm}{~xPr#QwfDz4877ggbahE4(5< z1!pl=`hD<0Mq_ovx@Cy_!i%4b?SvM022ktWcTMp~w-@3uF$whtA~=&PN* z*6!1-?IV)2zw}3f7{$(vl-2mDF%i0=uzt^1=9vQ(B;vS89t&VuFHN^z=`t-R=Pz-H*kCb1(AO5LA~4w zu&xE6H`~7yVtgD=pr43MlU9@bsgoKehkDoMDPpSU7&mMP0j97 zedt!dW0Q}^H#fIgbg->GFVb)91?@ciu+6J8F1Btlg=^fS^jpkd_yXWloN^MKT#|pw zYVJG+S})>UU$`J6Hw4oa!KkkFBwfc{neQdC?Eb&<+B%IS@z|Rn8j@Dz_@s*ojz0WB zDkY!chr_+L@$Od?igCp>KDx=OJLsd^`c6f-GbTeYE68XRYMbR>)iTm)=`6xLZQ_p9 z--P1V*E9WkcF(Q8J(zNx#JGqDFU{Cxj={HnG_4km1q)JJEYPieE>f z+-b07dnKOiyg*yhisZ^w=aV{p!iczoUQuhMiki=Df~5m?b^ar5`=rYf+!L zV?WM!S%%jg_I@i_eeGBGH3Z{YOB4*`(fS47XqP}S!p*GG7|C=6L1Kyin$Nue z_!}%6^+sK=CKZbY@JDn4^QwD+<)Ibz-9Zf(iLR~==R%xOt6#+F05`qsscGNP;BxPj z*CHZMUt1(xN+jyE9kkc%6z7bwfGD#6JRQ@WowyKT5Wgl3WSa72M=SC|()qA=PU8dD z!D!f?e4uEHt5FTBN z`{s-`-N^d5)v{O1x_UwZ^%WziBVO{YM{?bT)X{0&>(1Z-q<(w=E0;Z1?abO1q2ZfD zDGLD0>GdJsnWa?T%eg?;3lKXT3=Ip>d@b8cJx$T$C}n=NzAM7=-L5gFh@#1e1z@xiRA z3B{Gss`UOqMH?`DL=@%AEUU&TlCbv7dW{E~x7QV=i6z zdJ7moFS|WtD8bhd0{#`D2pIMX=>9oak`%)6{uKdo=N!!HdkU zbLG|FlVl9)P42@@(5HaF){y6D3MWw%#V3gMgBUT_=hD2`$JjiTdsx+?!HiK>cGXk_bKqcSJQf>f8FV6gclM=HWj8nS`who;F zv&ZFLa*VJGaSoeg!l0Q5SlAH9;MKdcG1z+at!g>UY&Ir?6zUx-YwW()qM94UPfzB2 z+vIP<8O)O3W4K#%2c^N%nh6L;jUwFIR9k{s@|{XES_Dzo@zsW+_U7XUJv;04G{T=? zZcOrI-3973k*BNQAyvXq(L?UZJm_Ef5snMbW;XFuc(hOEK?g`KG+@0MubVXKU*L{X zJ{dohrK}#;$Mw_FaS#^Xjg=c&{q28FqZ zyD(QSAb@IM(ap5H9z9xsAmIG|DgpUt$p-tP1mNH2y)pgZ*Ay+H(|Qq4_|rN6NhT+*C`mX{je9iS z*X1Smc3Bbj-Fam#PN|Fr{>{sTe~aPH^iU|vXy9aLY9rkV2VKL&*VCwR6sl5I4J*&H!l&oZ4R`! zE5*o_cXB~n;|4YiQF^ea#LthOsi(CkctMG_254ab)Z;baAK!%9)Wp3y;<>}!pyt}!cJ)8I)ql0#>4zuP zKeiALxzebuQxM`YWjxj)Qx^yF55wMzA+l^bEPam#*Ru7587DR)XQc?J>y_md1O}Nx zm9zzJ<#LBix0(~)2@=c+g?bqJaa#{t>IdRx@t4P>g3>PW^WCE_T8M}7HIn)H=|^F+LmZ4 zJL`gWv;%>&ARzpwiGTFVA5NL*6H)>zTU32#0>9;>+3+2sM*dq9NQ$gAdZ;&>n+<`u z#lXgnyzBNA+ES{2yG%6=3(Frp6IVQ)Ory$O=!78@ha9f+c1lqs72)zWUf#1QePF$) zEY=&BYjMFEl;ZgSVo5^4A<8GmA%^o9&SmL%-pa@WoA8`z!1PEx6}&_(Jhs!Y-JVGnB3_n4vdBiiLVfqy=<~ncLMY0cOhc!#@;XpAM8p!i6VdYEKF3NxD=>Bn_O3kcfcrUVbtbL&oYUY5*_G&Bm99 zU+xE=w&YW=Pw99(M+a~A{U9&m%Vd;F6Tw=Nrcz}#fR&M52zJec|L}pi`+g)VSCk6d zR;&A&jS{GijA6bxxsYcGXuP+$2nL8MBY_~8@Ltk5*xrV)bUq2WTlcz|%eiH9Ceu!k zkF+rbuzvLG#IjE2K0dd%W=d@_k~n zh;5pq=CO`F5pU1$$HL5VTTHe_&Z6K9q@c9tyQ(b|%s2sgY=+j_~gx(;5ej0*hdH z)5q2%qOyVPI3@vgimpj1lHucBh}tGA}wC9i?@(Mp1xEfWG(1n9CponZAgoiZ@cJ zq?2mZr#`JI3RI>t`j#qOgh&?R>WGRLhCBcO&6;H#At2Ib#1x-HSv_))TNjOE?(L=W>N`djsj8R-Uv(DS)Uppx z+FJI@+s58&_Rh$V2}m0reg>BWMzi>6{uD-!hzj4SPuj)PwnS3LlQ&t? z8ks`Z&bxN>!`2|Z4|T^)Z?dCDp!$!N?mlb5hRH-|JKjSQF~3hs6+=Vs)D9fPW5G-f zL;w_Yy`ddT6?2Qe*SEqCb5O5v_C0Sqbcau(sqtB)l1KhY7Ql}zB*%kz4ZyUz1AKFI zuV*b#54s}D9OD;Zc>w00^_S4B;+d-Bk#dK;a=@W>g{7R0vzizxr#*B2n2a*O$iYaA`4;A421WBSBv066tb& z%kB$NnxB`4CNt_MS*LO+I@VambUa;8CrFqKeg2XY84VV*dsSOk%Rz&;*)|lmrYRWIC61@C~Z$wJ4od;mus%?L=+Wwp1NE* z&oH_Os{G>F0+?kElMKjyqb4oHj%;WyH2fNI@7l9Vwt9<#;J+?HuYE!=+2DoVnUyZa zzN8HO5$0(ysAgxraOPF0Gn&sje=9p{0ET1>;b3T4uPzZE@std1sJQllDy}VEadtLM z)4}~J6&OkE6G7}d~62jVz=!SW&(KE8z>Q&RsbhCtKH|x1q{!&WZ%9M2tGRllH}kTG!V0 zhR*(cl7Mn#NlmK0VoD^YC|NS0jn$c?(Der)OA?!3lpIsER3el5-lfT`& z9QG(5?Ve>&eJJ08(QY#>3KN?(N;<--KgW7g=L{ug0I2E4ymH3F)@Me*hlex4o1h_i zX;>JzMW7`0Hb{}N)TF%^Iv*ZwqU5eIwMbV`TF_XO9X(af5?GrL{IC#txq=%9AjHGv z9rT&&dx8`yR~U8b21rQza9+wJVW}p8b_qAxKu&r?5y9L3KXzDU?Mj4%XtD4jxB9Vvg|0yNzuZG z$?$}{Fi!ahZIVqLbwsnNHlne!Ovt)6i7u~$?(@m+SYOtJ04Fx$*|x4T1^TZ?+-|QE zdMI@kCf@5!;{9!*W0?n=#f8bQt9rG58pFsz*#1=r2HoFSl3q~OWyl5PTa8+H>LCK+ zEndqOxGDm?UaG%9U<>#(Nf5_>1 z*_Ft7WqHw~UWfer6E8!m^5#`YIf6wfAKV(G_Yb}Vrx4(iWfvi5UTPU~&igM!0ke21 za(aLn3?xinW;Jrgd#*=@@guHCfnQvcE-_q{LAiUaONKCiWrj1rZ%eOE&TZBwznB#& zZ$I@K}xjb`L8fs8)c*K3Z^bke&-)~{s?#*J0=9uCS1QKZa!Bo& z?`o~r&M?~*n$j#K7Flbh*h@er!0?N)p*t3U182H&zAmb@N&22VO-#f?1XMdXmpvJ{ zQ~hluz^}&FiY-!fvo;i8@62!~(|n?Av(e#^q#&=CaPa!z8CGQ)008kd7rU&j6pgcUy;_YlWCAoxdA@lldNmNbkii``-kb|z0$XfFr3v> zMXt*U!gJk$b}zfg7)scZ;O0X*Vs9O!wIp>g4Z+v1bpvLdlYCKJj1-l;NWw_~;B=DC z#;Sw@y*AR9V&)C0|mXS z`>a6iLG6lyPN!2NLc{*h^Ej!^Dp`JWi9=B9KAI)w9kt~Nec%A6t#HSt>d?`EFYe1r z74vuKQ1Nx}<_sSR@=jWjw{DN;Z7%=jiz$jHAyiQq<&Il=MO^0 zA?H*!fSr!0->E*8Xon^>A@CY{-P!il>goslp}+OFoxOMUbv%Iz3RS?1BMA1*Cb`ey z(lS7dF-w|l@vk2AysgXOktFLW<7W-QE;)eYt=*n@(?WW_$qK=vy+d{Q?2Y;@Zf>3F zod$!Bi{i51(1=-t(S@H`&6Oi2vPJ+_pKbQ1jyz>kY#l^zC!kXTgO--I?W_4WCukMX z0H5l@pxY@PEikPYHzh=$FIsw(ip56S1x=%bWW*$!OXB!kxEnvu*kVq-tea5w0K0>9 zcbnC;v|-u>ltTs+|FN5mhuP^ZVDlNw8RxUWelYA=+C1ToEKLVU)c4e*nM?&EA&-X+5oQ4t#KF{n^WZFScc z2qH-l1v8bJ8@X+LYT^z`Hq0GiW-OSo7a)49nS)hh+>9sRMrcWRC$-<>atM2Pima+9W@ z%x>hq;pF*y{pmW6=9E3!dwuZg4HpeR-CFY5?wegM=YQ}^k)NecpFWLO(fMc>lcMDf z3=sMxh>qr{fR-=o^P7%;#vx_9mpBn!rcTa5fteCJ_9ROOvuVO23hMHY5d}XLI6M~J z+3Jcp8*J{_3kFxloC4?!@HG-O2faod#lqGxh1LNz!95}F<>O|#`AIW|kqBpfw_cg6 z^Wlcy)HZI}Jk*+pmrC+0~FtGj`<8zX)=f z8V}l6XhDC{Rj0&tx@a-O6f@aJ*0g8JQZv?)Q|oj<9Pwp^?07dtV&6#)irYD=)JVGF zi#izbGun3sKqCrVCM+g>Mi=$fJ;#2^s-mhu2Z!Sg#pOWLd@v=S*C5eP%95(<8+AO$ zFmO|`{0L8p!$RP;oaO$pfN=ZUI&Ea7Z=7u^fTDk0BhiDo^6FcnI;jB@I;W;zQB|q{ zAp}sOyW}8Hxng0aA`sI9>cT-!jgmf*6Y-IWU5XQdBO;}=jgDqOh{z8AAaWyZJmx__ zvp1aR0)b>h={r)QsYQOil>tH_q6(^F*P1BnK#LBJMVq`umaY{wIs`{q-2#f_jP0p| z3XHO%!%jSGI4=k#u#zAw()VoaN+9S4)oAgg+COP|6#CIxq{OtUZ zek~Zlm3W@3qPt9da@!(MA4skju#DCQK4{mjqePU}Vw@?Ij_D8GGYXAb3AF)E97{^i zjG++qwnO(TF*15b-}dseJ>ugvQNJKBvXIZp9? zm*zCfpZG;@YtJ)ki8ym>D#BP|RzJ7e5x(|t%*yn5L$mBmv3ewQU`E9@N~DbjP7}aL zl;71q`2=ML&xodTo5ZGQG93A1_GfQc5Vbzz@gm-ckC$i$^JC8!@|YUGvnD;gI3il46fMunKLUy6&iF4 ziH&?_aS~k2cNeo|>q#fp5Mp;If@Y_D;N?O%-s+HNc`z_g#wdl8?BvJQ=h(sUrz@s{ zMI%>Zi+*F-`9(|KR1<}k1kz{qM-Uc``DMmT08`iT*oMo9`8_7_Xk-uX0EMTONspZx%@`-DSVfN9v#O3uO;W4B_h%czFZ5Dv-AQ$u zlftufq(!ZmoDRH-{gO^1MpY>qHkl2?Xwe?TMUH*oMzo|6=s!>HDAiM2bQ42e&}7@c zL%V-DC2`Qo>deb_X_Eu)gvG99-1wGke`=0%+NNzRg|R%r$5AytXztF2!z(o((vHGc zstt$B%kS@Dqyi0Lp|l)kTVyIhJ!tWKtaj8Aj5Wh?L!7UnVR9&T=irW+Q|7_Gl5jQnKaL4IXx15#wVpXXq;-s17 ze8ZzT_;B|tH-?cF03n7Oum+j$d}rDKAEkM~_~J!3rJe>ymO*EWm_F50C(XN!!mLbC z9wPnV?td^UBG4Ao5`VBw?vHfk7P=CS+5;md!Sb2k=IC}5S$Z8<^5Vc0iHxNEM5HFX z9`0%mtPb%{Pv3UQ9TsU$HqR4nTgHd34kv7-PO;}J%aaSsg$t9(6)-y}${^X70GY^? zSV$9A4U*f#cCP}E82qqHq|LEMdv0|6@e90aNb(#qZcHQf>4to@$1Gso*BmEbp~Ki} zR$ArcgGm5it7>M;p+HS>za9m7Team{QI+m*DY^p8^W!jm`QcuUz zde*xjdzAZ=Rb$g3V{^(sVvVs9;l+{it#r3=Ob->N_2$G7AHW=8p0zYj}{;vohL$RD2tj#StQ!U!229+y@4En_VL zb^q?)_p79gyrw-OQ()=nQ)LNLlf{MoB`jA<{LIX);vqc!*z)dV{H8vxgYw`wPByL`uW|wgzpPE|ZdH!28*)hi##h)AU^n>}?n3;R zzx?Ibzy5VYk3mCT<46~M%z@g;TtJeDL;umb-MMMkL+K_0R#i-BNubNQz}=YwP7TFe#GM$5P02Ao+G^z(u6j^jlgt&i z|B{mz_YDPW#EuA~MxBo{m9o!&hSAp&Z#uvcrjdAYATH(urRqVgq9td*~ zg1ZKz#S(~F0@QcO9)5bI?Z6DfUW<%J>qcyYass^e+TDmbFlP*C;>J}pAojS7?Jvk{ z`R?9}!@b=XSV8)!3ehJ#o4sz6#YlTlMM8MF?YeXw0mN5t4#^}5FwEmTAleO!Eut5$ zd7N8B8hca466+su+{*$;5;mF(Qhf(sK0ib;^EjsvRZXFMsK{fEYJHNB;Ux#}f^w*< z%ms%2024%ZR4K9;@d!({lehujto^Ze$p(7~FH&MX`T8EpJ=bn~8S?3bIJ*s6bKA)O zr?csFyj`ykfb>}nKACFiEAh7-9SjTIX z(109p*@XAreF?wzfPKTj|C0h%A)Zwx);;+eZdcb7H8wkA4giqRW)m+E z)k!>Y^05c%2w225L|iqxT>c)vRdnY%mK&aU3_gP$#QLm)gp~10qDIVwbv7#GyhJ`g zp?}ZzUtuKq7%tpSuF(=`|2*G5I{HC|%*Bt?aEVV6QS*c$47fz*#Dt!XI$*+7y#M91 znDU~!{?ssDau(hf3sjS+r!lI%`r`1*e{S3F5kNRIFIHB_sE%wfav|x!u?_WaSkReh zVT}K%f@5*5dWSHZUJb}P)>LLM=9Kja6xr^(l@B;?>a@<-C_OImJNp-GL@hiE+tQ#L zpM2AIBKE|NPnFsP0=g`n)vsn=jFIiIN5jfyT#7Cpp~>BhTH5Y*`(zE#9_Vde3_4@p z`VA**nh*UkHe(Giu)HwXEwR`e|x1@tzu zA)Kt8&0RcJSozpN&2zzFlHjHj3D8{Kck52uFg`B!BZvigO&fKts!(@nIh5{_W1Wut z$@yLiv|NFfDG(?_ok%DJ$WL{7aoHUn6?YVMLsl`U8l^rzj%-B!L#KH9BPIpg1<2~> z;Ej%6Ai^01A<~#TN|CD(<2R-jsMT7);9GBAf3@GRZ_jsM9Dxse9J6!~X2RE8KC1ke z?KSd8FpWCxbXHQm&Vlp5)UbPdt0`B)@GpCAU<23rJ;gJOH^oJn~0%`$yu!C#zeIyl2 zSU1slJt+F%*2tW;&NFGcAH^^*78o=A6x5?=$%Jb2W=u3sA5EAFCQLFicGLpnB_!l2 zF^zXfseSB`e@hy}-<9WEjhq+2JUH_HK?wUtj&Ef$K9}QrNCf>C$?)m(jXW(`QXpK7 z7JOX#iYw^1U;lT7ht8N^*+|=ggakx0I}2RG-ssgu96p~>tPTb z>s%|}ot&KjANEKaa7RBqO-FLVBDZ6Cc@BM-|0BBlCs+E|H=0|QIqIgg&r{DY*<%i@ zZL8LmV~7B)?fFAAdMD@F01caE3O%h!IdcgS2Sn_9%!UahzX{0*57cr~G#$x3!V{^? zRBpV2&{+rfV{Z=(86Rq(qyx31EjlF{1WFB@9i-`H5f6$e`2FT@VijMP|6&a!f5}_J zoL%8=*DP}uo}EE0xfFz7g6#}}-q+C61NA`dJ|EH^^nbJ4gkzLPx`$^0`irD97>KYB z&iYe^qdJ7AU#AA^Z!4kC4d(Dlrup8sM`GCs!e_E()U0q z!~QU${f|=BW`~dLmt@ZhG_v{_2$P{zqWwn*(KboX`(3e<2QU;FibIw5i8I2I8f(## zgAr^HuEi#%fDDVc>Z9)K^vFGOvjSL%~S9loBRQQ`9xCT9hVEG{*ayX6u=9BN@0I2fYvZ;yERQVsJYoZEao24){=*!ZZR1=G+ zp~|-BW=kSS-e<+yglkP?P0L_mn$=*K4U0&*T7q8WtY4z~I(gLfve$qfb!bgS(`ZQH zV%I=ViEaaLvKvX{_Q6Iu{FuwrDCN>syN0=tzqRhsKVRYzTd+Ez z4<(ASGP&|1z<{50tb>h%QB8#t-5~qlzg|+*nWH1J4MwT}04>KD;#Nc4I z0q9~qO9X&hMT>VjW5Yy10{V!F(JFSG##Rk~Ji@}>KeHunQOzsnGp@!ks-<1h1(&9D zns;@IhHTy7!`pAwyLEVC3gQl12n+GOc#{lMaX#w?@VVi_6hBH5}w1jM)%OIhE`r6L6ilmL^X8;P;os z7()zd>r_F(pMrq$&4-n9uxsYSK_z0E2Ai`Qh}FZ zQB51@6ZSiNEVp}y=;c8TRAJ70+P&Z3D%n1(C^nHdl z&3eBF=`e*>y9P?3B{#jze_Kc7qIj+;brk*VGUD%luS$-mG2ys`)AJT;wu*eX zs;cAW`@eVc=CMGQw4_LwD|e7qQx5#20Fjds-qtP>iX51pfIT{=nX5#PNn-Eh!SMZ57k)rAb9+~(7yZ!&hhnfb zh>xMiyus+3mDq09`n3et)Frm%G|fS;=%Am>!_gf=h7TaelVO}^yA}vjPHfsy{}a5J z@|mO+*cqjAJGYv*aSL^S7+OxVZKXrd;$%MM*j8RH^qujSR@N$88}^`3#WbI;E>A7Z z1`rf4j!l>-RM52~)GUec6YdZGz9H!!LRt0LT%!CFRD1ojcJ^6Lef9j{#lBkafw=Ur zZ1J&VK(mTzLzON{m7U1ww|X+OYrP6Bte!-l!kZZFEUgSHD!PJN?G;Aw!=b90s7rU& zK>-hcz)%wgk*A27;=n5@7;Oo@0#HHuex@~B(&34E(~z8>v6-aO3~pSw#-#8>7@e0li^u zG)T@qNlaX+T)MT{6#c?O+AcxKtVH7^*sK;E^eCc_8iH_=f1Z$fu~$jdQmxYYX!&7&7A-=_Xwi(^RW{oB8H6Jz4po$042xtTh(NXGnihl< z|GP=}`K4(C7s^s0ohb@at84>jQ0tckmxah z^m~hU4eBCl1Qs(@HJx<$=5;XdVFcWn^sJaPN_`ZaB%wWu-`Ry2J8#&5SmB50K8PKH zT7ckTrh>eeZ&2=D&R_TT+%UnqE%EdMe_-;!XKzSkhR7z$@AADYU_6ZKv>{uj zs>{f`VSyX%i#wgx>1vC?bQ7klOh8+`LHm>@IQ&8wo%?3xf?PXvKwUjH+;Ng^2;ZP}RdNXS*Ge66cKJ4iM*qySwb}Nv}ek zwXNyYSSYK5qeHd#hd&mH`_e^kBlDd<{BdPMAA%t|ZRS$$?0j%VI;=UMNuQ@&&kz$8 zoH)sDI|S-w%7(Ra9Vi_j*ar<3RcPWEr-Ni9cUWKV9jV{dejjJ#ZkhFqwM=R^U{7Ww zW|MWuCCP+Zd9T*iC!LJ6_Z79~y70WCSLm=|5&h5?FdfCNNJO+6V^bKV9*Vvx@D3m{LX zYVCYuT%j){0H1Ojk%n=n6arh(*)do6gg4v7jM_(Ie|Yp#SENQ#85xOw@- z7qL1^F1c?oxk-q8^3mxOdOO9ga5LjB6~NBHLIaW#@oqNip-r<9Y&!;57&sJ!^^c%P z9~eTRuBQ_ITjGPO_%f~msE=1D#%CiI>;~Y%Ev~8pKhb$IR1%Y;(}d`@ae~YJACgB_ z5RuuWpUyH=hb}#N691}!id0+t@?vWfAI2Q|cSBSWBW}=S(!N4d|ARhF$;vO2VFWUd z5;Q4mi=pxbLewW3bffV^w}oegqS-J%hC?5e<0{zuIUfvjA7n8QR;F3+DXn*@_pJa_ z4Jb?0pVcPx1=UU9DPh6E=P%Ws`jp$cd+-g0VZpS^WcDdU4}21%%}^dgS*gaDPP8tW zFh2A->OCziw3bm}?t}}?(0+`cA0DnMq!|>TX+ApS8Yt_0>16qr?qOPg+0JMq z@(tV(w*>6O*(Ni`(YS+uX3OR}N5RgGc$w=d^2SRPDssit%5$u`mMzpzGS_foKvv_E z17lq0rkF{BI~s6qmP>*67xC}XhR*o}SAu!l>!$Xmbw*DUVjm8z(ZASaFfTnDGZcWp zXo#B@(N*(SZ=J}CA+%giLc3Gl(yWicP64Z2zZ8VqiPMqJQ?D^RM66erV!J!eB(n>;mt(Kq}Ot&N!UUd^0-T@QX~e zc7iiQJST0KY0uVzKqhCFA48cu`MF!jh(8 zc(4xk=~!1)DZEJ2f2!o*5Nj{nsd1OD&ou#%P=Wv!I=bVW`W%7x8{5d2A|D_g##Jzb zHVmf7d{Y%m*+)E}OxHLj*v;fs(O$VG5X3G|n} zRN1A?eUb2EeKB#cY!YiV;z|ntX67wkfj@f zeFq~bGz5n65LD#Z;|4(J<5vM^|&@wpcw1Vc=_ zlWb0|CA;Y2L|;&BpKgHf=wRUc*-(^)m=~fQRI(~XjRU)@crY+f1m{mAtc@)DwM5I*P>w!5?z2n%HwZxgaHJ~I}i(i>>+EF5D{cV!|{Wr>+?8P@^ds2ZiS z(=)SwpMn`=EH_Z(-d@|8B=;v)H;4i9w*d@&9~#Gw9b|{e3$VC|$9ZfSCEC=VKG|JU z=FfDdVX?fai|Y-t5fV_%oHWcjaoHuBR4)H34C!z@H|Y)1Y~eD;^>jRhW)E0m3_6#i z=MI7jgX{S!4@fB{*C`nOJW0+NMN~ApAM}iVaEX z;whfwJtQP$kX)>IYN19_brnQFq=H}s??~nH-}7|$&d$yb3%d)5ImfzF*y*14oq49; zCVVTGaaobY6vA>0r&}#vmNET(!;9e{a8?#|3*CVxha3q^*&B@juqaRt2`Tl$z^ADu zVk3|}TW8=4R?k^hyn%P)gyy(3Q6ho(5?%mx65)0`Dl2&lMkEt%s!H%-Oq{{nD2iW& zK!~y(aGs-W;vWkTf4s%b`+9qa-ZlI!@(bT@@@q(9=u*Jw5oyV*XtWYEu_Wc8nv{x;w6|YsgC+IpIueF3l3n{oRJBxOfmJ|PObNHxZJJ>)^LZo&D5uUw< zCSr@z&^GTHiYB8%*3JjbUXn>UvSj&dL&a=kH?k}S%QvW@xICj@DB2Y5ra?8DmMMzT z{__}%Gc>!-@i1z?yw~|Sx48VrL7A`fmIt0rd{FnhsH`;1SLpl&ny}1f#@KpZ_2)-$o=vME?k(!AS{yWP>y4F=4wdbA4+ug27NLdF4*lU+d8 zQNq})RVCBXQ45>Gc$?XO-mkx^mb`tEPl8}L=!&wFm6g~JgzBezq+bO_Aw1Uj#%7|Z z-%x3e*za-R+w!uMlFcS0lU=Wm>^pY_wCBddM&*Z}ykwQ{b@L4>iU^Mo#xf$MIe~2m z`HS*}x@C(qg1j%Nfewu+2ZHP zQm^M&aB+y@ z(9dDs9WRDgSVkcp(3?C%lWjywoPZB=X5=$TVa&ubZSGCs8#MbOt_3$TQ7<$j^`=oCshAx zOAMf`4P@Xek>uH6Xgzu^PwZ)S*=+mqTy^d^YfNvZIp=~I=dZg{YVJF5=E4SxQ^?q~ zh18B=M50$VWnPUP^NY&y!P!aU{HXRTFl*!BsIm(S=3*Y!0~#995}Ro3S}8`am1X=| zk7xv2smHLDbQD{Qj$eLygIwRUk{{t;5zrkj$bJ0n#h$aK<=7g3kA4GrQ zna!B5OSLBam`9PGFLBL!!b;cWtV@zt-0GyqO;Ng)Dv9D1z4UlBuhC^Hcsfn@y5N!( zWD=u&eW>MYO0$ya0Fpp$zh6NXRlxGlV!d+uS6lxoy`%ds(7>t>4|0R#=BB$t@?oNt zx;rG7p_`=DCyQOe%;1oC3lj60LX)0Vor`XyFFv$-}L96j3PWHbW1qJ)$u~o%?{A_Xwg<&TU+DjNY$+ zlu3tcft6QxoVDhf1T(`@%51R%Q|blNTtdy@lx9J*qEq686iL)&*zqYPaejo#*}2AM zsm>WsBmxn7>3c; zaB^57>#-e-$Y$f@I8Kb!Q?gP{JS_ux-}UeNdR7x!3gj)UBxk+qGnFYX^0CA zd7kvV76L?dYLcE!a41XQo}hI;tBit!wdBjE0224$IYG@P=4)FW{S-|P1;{wk)ebM< zbNK?Zh9SB>3!=(?gB!y?eQ5*o@Kp*y8m;=QKk)6=08EvM;~Ag7uRBfbUVL!ook}iG zk?jtz45Mbbl=Ge!PhrQmLPu?m?waCx7u6X`|epl5lBObQud9ct;)%sB8=@I+1Fo3ir!Bl9_SX zsh@6ngsrMHTa+k(Z42)R#u~DLXCt~t1y$S1`EZy~LO_dgz{EQFdoXTJ4Bf9=JcBsrQFGAY-lXI5Azu5I z;VgrFktYRki$9k~oQD|Y`lszqn=um>jin8V>SoaCDo}T)?9*^>j_zBue0gjtHnm6f z2prS+jzs!PHO8zrmxNM|p-Gl8VC;fwDIxoncfon#7>UL;j%(H9+EE2|pjGU0cxCt& zb9n{Z;*C1`vv+$7C>t%hXVk(jnpR_@8KHg(nqx|mthKxBukj3(JWoBe=%g=aWRMMN z39kjFq`-mkapE1kkQ9Xm#CzjE538zAXEznPxt=lh4Be>R7v zk%Z_K+&Ru0zwDmCr3%q!s*T;_{ji^V>+ddZ@#MB-Y)HJz{0wJ!ysbbvb3-)srzUDEw=5Q33|HB?!i>i>22R5st&D$c zAx_#HVr`(C<7>>(z3jr8K$If!zsjQ*&G|nsF6aHcknDXtA64jkU$aWzDm?#j@R@2q z=Z@>L3goyA&SpNwX`5oOY*%|96--(LNG=W1GhkZGN zes8dAVPNS3AI{OD6U@bzhr6$;g@gT*Q{=Hm2T$K~n7giv zUo=PyIDmSd(N|^d`stTtcwh=cjLWFbB_Gz3tEG}Fh>a**oZS7~=>t5AEgb(Ii8ClQ zJIWg_MYgdEvt;eL#yXS>G7oqTPQGZ=d>_jZPJ7Cfu%ZQwcrq^UnD6XP@w3mr`0}f- zaTo3nc?~}Y=qTT!tfZn#$brBhGQWj$7~lAE)SEY+`PAf*d~aj39rPnUxX;-7#wIYk z!T{4W(Y`lWjH(Xrqi^-Qkg^FU!Yj`tHnWNQdZ!{^@6b6n8fG4rwxgloJ|WmCnsb5Iwe{fp6i!Tz0FGO*B}6 z?d*qDB0Rsm(Aaq4VGDqdullxLmY^u_^RVD+rgwH^0XKV4ujMvK84Shuh*uw83R@~5 zC0B+ISiImG2t^y++lv8h9}6fhjm)gmpP3wh1dj@~QiDMKNCv*TP7vcXC0*?O^wCPkP|= ztoGB9S$~!RH>HIQ8i=DvGVb$7A}3dByT2Rt{Il89_59UrL%$Vj!$Bq5YuykhzHH%t zIQ>S2<;57jI^p&j$sO1^zU@G4NMro!yjuJ9#4O-#bBvbx%{t#bMav>pAoCCDCz>WN z_d{vQ42amz4u3s7IzP;dB{fZHS`8RW%Jdcxr%fU?g@4E^sZ*ZNmlcIyV1Uu=V<8Ah zSd#Yz<)7v+)GMrudFRohNjB(PFE(i7R>Uv5&o1&C`QSjfGLJ;wF0mSY`02+|;SJR? z7LWHJ9^*~pJOA-=eV=)|TY`U`zemO{sO50y%OmtXu(wxemr!!?BA<2JiYwCI!Qv@p zQTO1z2ycJ^-WZvs<78ww=jn-Ld* z6oDhr2{!xvY;YhZvofIHmRck8vz+1m<1j>=Y^YM896aRUd7pT}mpo4%7`03LR_}Tc3Qg{d{Zdnfiv07wdPtr`OtE;%806L~Y%E{)zWowb1^_xPyps zwY~P(TMKV2@qW))H;w6iVr?1mbh2oO6ni_CF4zFJhkw4q|E;hX-cNbAJs8seDQUqI zUYt~$r>#a(kC@}BwhNwL}dwe3TeYfQMoQQq*k z_g85`t(&Vj@jJ64@}x|C_tZpy3po~To(DXY+@ zP`=3(D!gEt8kIy#b|Pg94=C?XOHsE_M)uLeOxFq*F5FIs@G7Y^3P|G}i|Q4+O)2$C z+*nHt6R1Pr-brD2szRM=4nJ$l+H3a#m^d4kf`sWR3bTdfC!7C!J_btyS4+K{r_v2Z6hLB1E zI%wfk=ox^qY#CfPQ|9!J_g#FTjPZvtoW^uub##rXp;?iA_j!4=yF4 zJtSKz4WW^=GLe7?bn6fXMStQeNAzK-P7MEY;Dy>yQUMIblnP=frlo@nm9c{v3&0HZ z%mx}d%|VSMP($^W0~_ml8)R3lu8;U0};7|+>a;$hSc90_}p zI<#p3N|ZM-P>C`+z_Q|<+yRz#02T_webpbn%>-B!b0)x|m{$f^Q~?gKECH~n&a?rG zP2&Jd8o;7@%>kBmy(KFHENW=802alY8n7rv2Uu3TlRLnY6tFB2w$SYE51RXTrB1G*d#B5NArjf(38~$;7z=xDv|Uft7{8ia9q-s1hY`KqVPa z3C&IiQ`Yu!EFY$X#x)&C2{ERCC?PHfP*%NjJAg75pe)la2D?hJm=%%~i&-H_vA9Y| zQY<=1vK&Z)5srr>Lf{}tN=Q;HI!LnSmt!T6q*%-dNs7fRkfd02kmO~x5PS<*ofW?4Q4;cOlFSOk1<7e-NsPH}J}5!~RuayVmM@4@nM1`lW|fWaKe zkp+`GNU`F*)w6WJ4=ZRyQz}DFJ6%Pt4M)%z= zDp_cb;o^=P7dquEK*P=@3-s`FX#}}6Rs}}vk{mo)9G=9_B@?j35IYEy0>aoc*nyh$ zzCg1fH`(1X@QTOgM&g3f)N}PN(zORZV_VdPJ^K==ZgX(mCvHkNagbo;7FC_ z;L&p7k?Plk07;QMh?Ef`{m0(bHn(X6;qUqtR7o4VjoRAImn3y&T-9|wlSCfpWzvaL z21!_Ef`AI-SgHHpyLSg1=)l~;A#8U&eX(Kp?zr83_PIAmIuJ=xS7EdXl9X7vAx%n( zX+o5eGLR~@%ps5}$x z`qPB|h&ErRJtbmDcckc!=&wj~x(XNlG)J_q61@@C&X?YV__^9VNnsIcQzf(rlNDhm zMd+U`DXa!3Oq!66GXKdFky1&VHjyGHg^r6eC!NKOcEVC3Z-op zfMjQ*WCt2H`8=Q!Y7{4XN^Yghh(5WLy(zN>`Dg zpQdEYszgpQdh(Pcql84HDjj~V` zHKIaQ^wSesERvEYq=a^%NJWx6NI;|r2<1=y2I@|jA7r*j7 z{F%9b{qSu2Z2M8h9}|#eZPB!2cC@R+YDT+CjApc}oz0APk;yb*GGK3!#lTf$Fft5g zw2SPeE8o}7UPikr%w@DI&00pg$XHrV<;Ym784LUoAH^v=jRW&`=Z@RvX`EoD#4UoE z61NCu+POtALvGQ4TY$YqZUI-3TgY&WV20eHE8o}7ErOW}w+Lp^+#;A&a*LOvqbI|Y zm+#(~C#R#|kD=X1CiE7wGYL|jS&BrVvvacLOr@2&bniRBBcXRG5Su3)IKaK<1KeC0%qJg4fLnHC`cOSs@4;3N?yP2C9Pj(NvbL=JzMUY<`OpoL_)WXEc>>ZQ6*{!x zS8v7Xe;_^GpD0vM_-CTb)HC0oEfJ^t>+*%c4EaKdQ{gmzXFjc)FPN3H_&H%&zF=0* z;UiyYmPnB=G~)}cZVn*nUu}N?(U9CC0HV6L2tbjzML+{*2#_?axfL${-vY1J&Kjy0 z|3O-I@gGES@xMWmQO+@HDMo*W!30w~!C-#DLFujYY3=DnDZ9ugm+IVtgVJWBH5`4*FLG+Yq22nza(Q@uZicv{1%1=7>*bgzF<1KCWk&|$Lr`MAYzl2aw z9sx_1u0OV1!}6x^$AvSU+65$}T1O-w6e|+hIuxU)CpE>r&zlXo%DAGYD!d2J=tCOg zH~BT=AD+sXnMLifwa7_cVc~}7H_nSSGeNc) z0^SREsgw2ij@!IM;dWbI+yn3qXh>!|)o+Kxmv2rEhvxCClhNs0BU9B2?oMC}$zl#a zXes98^!WY3+r!jp#B#uQ)}i1zQ0>r;)~`SRmyTOlWUk#4VzWM&Oznvq2KHoY>bmw7 z8MALwl*r$4=JZY_%qW#s20)2uhY0iln#0UIHMUH1;#%I!G`D*{{bc-MFKp5t12&7p zp7FWigzzWSIV3`c@3||399)mDIuXm@o*%&wFdz>OrId8lcnLz04|XW|+Z#O6ug;Dj`?{XbXxeN8JZt z4d=X7NKM)!Vrp`yYfw$vA)u;oTZGlThz49Oh}*j8$Us(biAH56h)V)_9z-jMUJanT z3E;J&XyHJ>+orj-b?Jo87*3uG~5DzIO}h3Q}n!1m?at_TaC{8t1N-=oHp0J zJ%E1n`rQ!l-1zQ0{+IEK@x-{k&Rp2vhbtfwUwC!=dUQ(U_KltG?Pf?^*1L%%s3ABs z*U_wj)zW1P;4N7WbDg9Zkxy?Z2Nb&}&j>fmb)6rITeY4oDuspIag&0EOp+xZl@o9&{dKIVIbYD zVj?L5W*CrL6fBtPD2$ltL@3x!nDM;?Nc9)#d%<7=_?ixB$YhmQXRZzvnx3*WMaPduk@eNjpH8GlGv(A+}4JUqJD>9mOby-G}UE)r3b<&xl z@{!9ZaT#&bPu|G5??=|*kdJia?^^gsk!2;xNRg@x6DiU|8nT)Ej5I`^hKPHBK&)4L z!_V;PQv>RAtSJnM=hkH5hawND(kNS~nLK@JCZZ-2t-~~W`qpW@iMyQI#xD~%ROa|E z)~>+DzZc@tK>V`|Ne_6|+@{}?H9-D(FPRH`buc^~ZH<@bj}7RIZDT787EsQ)!LIec zo%SEYr0)9z^WgO84J;0AC*^`UEZ_hicYglFS5sJV)?;HQyTk&eSs#D?WPG!4Jlc80 zO8^fZ!!jqdcU^dg3jbUzs(00+z}9@p;|8Iw*EA^iUU0SIVV1`6!%{X+vV zbTt})&}~BlXp$rvfTRi!8AjUQiLpBiq-XP62_H&P^J6=jUCXJa&!H(mmq*?2+Q!OpT&&?|J zVkogAiy!Ubb8>q4_U)hQQN;9AgDC(Hj8=Cxrr1NbA6l%N*!@s)YK1}_}pVM7f3F{as=H| zAqJ4FW?3+WwzZgCn2A`OI3g~_Iy5Pa^f8&U-lsFyJsnX7*GHGoLU0h-3#nO(qtt!Q#Vo;3+Y zT8s}dNU9*pbf@vj4l4-U6>IqehdhX3!fJ!N z49UMecupH?>JR(LK3Lkg#0F#>Sh#|dlPCp{WHAez!2tb7kBmv+hYsxCo%%igL4?6q z@JS{XyFJ{bri5T53xyu(lE0VE!k+fw7Be-M7`U-Ey-2OyPp^T~l=%ddMQ2nERh-Lv zDy$r^hUh{txU3cy$*L7ycv1?fOxTFx9F&FFpq*UWu}uJXtqlU!mPs)$mrfHSZ%EBL{D4R={j3hdA3E&Zb5v z1zIkmh_s97o}g^n0ULqYw6;1pn<`5JZ7Sa-(h69UlvOS!Vy!54cffW6-;VxlHh^4K zfGqG*X@uX~0Kd!>5+KY3>qD_YY44MJg2=QtHjK*>QIkXGI)Rr2m#B3+keW6{7O$zW zENWBXyNlg3n2U7gc3tF-)unJdmPOR=8nt6Xlwx*X3=y06#Rl;@uCYE^#|0>1b*$4p zQpXLE!Rc632Bl-syMxit;0r&D#w*XNgV7oFN{r6PB1U(K(K$nuVsuta8Kb?>y(j3L z>4goUb7h?5&{;ju^5`t;bc@dAfCS~0ii+r5DtedD8Qw7vLRx`?4(ia%bt`b03nD0Y z2g=+E<%rB>6yca?+4p76nfJm*;Fwoe2aCD3BoK3jE>Tzn9$r|voQS`oTsnYGKw%w74Hd3^G?_Z zO7rUKpfuN(L}{+jB}$99!wV~y6H!`}YZawye+I4uLg7*q1cpn}APlmI!?yv4!4NV~ z3}T4J%x^ag$d!?j!({bP6JeR@+zw=hhRA|5h|1zKh;9g?&mI16FL@gVe;3A$FTxnI z_h2Z$1!GwH5)7@cz{p*#J6A)22L2hip8=h0cW+nBI~59LnFfsfAA3jI-8c>WOn!w3 zg`}lP5AH63SGp-%C~axN^(c6q#A(escCeiu9RHm;Y|D!5#&*2ieXngI&5SgonbGJr zVi*I^s&_L~0i>sOGTi90E+T69T6&*sPaGu_x?84*W7EW>on_ELUg|-H*r!Ob*W*z% zE;M(N4JUnx91-V(_5_ZOmHR_O<*Y)Y3CWphI^6)=ecr!3>z{%W?Zqt#=$eM5Jd0k5 zUQWH%H&1hNYtHQw=E(?;n%)ta9P{L2^2{^N?JXzOW}bJ!zEQ$B5&Ut}M2MGfm{`g`)-0unq)}=B|8$c?9#$J9 zLKQMc1gygtzZn1>-4vxx>4qqa?`77f(fAMDR#(;ISl9l_&Eo`<=Ue6`EG6_mz3g99 zb1U(ca;ErAY#5Ep|{B5+^N?jsHm&zqK$t@S%YsRQefRU36>huJGMyAhpEh!jN zZ{bdQQB!Bl4e%`a$?iX^OU;;va<;Mo%{Lq+dCsrYMgap zLMi%?B-vzYO?aswBHW|tE37N=?0eTx6t^nR;>b);SW-fs=^?)%-_^nl%MEPL4HCR1 zG4|r(cQ&G;Hd0iZF-ib_IZb#D)mG@>2t0X2pz)eGLVZl`YEnR{F#^l6#!%}JTAcm{ zf*KS#U&dBT;!6>qYvp%3Fj0uSlIA@ZAo?x9#(NNT_0zDkbn5^vx=YX@CG7307P7my z|JK{@y!+n!ABc~diCX~23Sf6PVC-m8EO>UU3Xu9OO(C4kS@N@6p{A-hOn073)^!L( z`k5B7*8&%>L+LHb&>JoBp#rT`)mwy3u`kUY)PU#1h$KvMPK64rl3I2c5?!jD>Dyqz z8*w9uH^m;9ifk0*?$&e~Y4;(aJJ%t&KDBvg=6z@P_tdN>>f9%Yhm%Ty2VT+N7HF%W zn)H0#3p|eDcwXXSO);{<(DD(3NEA@A2u`a@FR3j-K!3?K+S}b~@Bg^ByGgUy0f+;X zdJeS-ENd2snMY6d;gq+FPLHs3?tu)5E0OAiD;&i^Qg1|B&qS(?M7sHs=UMD8(wmjLC7MvA)>K8A8%aeZ?y!E;*>tGwXTJ zG4Yogc^DfcLj&rQ2MhOnAl~lYi&!-B2~d0($b=fqtl8E!g#olQ8G58A-TK=wZkv>x z+ZJ>Jk=@Ma8n4li%^C1y4>-6o6r#`1XD0Z4mA|xcwVt>UPL!jcM7IZ$cCc7aUg* z-Kg0yAy!7o%JnD&3L>KgkY-e(wAq7~;-sjK&=@&>3tFb#5-stD*uCF9KHe0)9)8;2 z#pfG&oDRBmdj3uSvOV4u?Uo5KTu;Df=$z>vd~5yEN`Vj0zq+`Hz*DFni`HQaBCa-m z=?EYMw?HEWKt;wg%e!j4@`@0ElU=UeN$VI`EA;(R8PbT#`$yB&Yw$}Xq0 zIf5J7>f%58+)ea(OI*)97vn-P8sR@}E`?{&9`B4smZ>jnljW}$Tc!BXgDV|^1DB%S zrlH@KH5fiUGM@DhpY|{FZbp4goP%e&Jo#3<(|rp@7!Sb?S~`UG6sCss1-yqD_2!N} z4zZ_;w{&oA08*j?G=2_3j7*Y#ME23p$9eukk^=B-RkAq3vRy=9xHf!->P|e4NCE>& zeMY7Bo=cV$*=!^ggGm5ts}KZs^SmKdkV3}@NDqNTQ7HlUkRCHVqmS@`^ZZg6yXdRim5FiVkRmylD{E&+87yF5NQte04KsQ~Os>)wB3{K_@c8I#SX=*xugvINQE~;Y2(KDf z&{8Mo^>JnT8GRn5SL*W+v1*?;e0q3USD(iNd7U##ui`fdv7+Mu&Q4G2@*H=#n5i>H z$rbn_ylQNHbM)-+vL>!F$9z@Cd)3E!HIDOO5y{Q)7?@neV<28dkI}!pJgduNIQGmA zGbURoy~<1rAy%AbIX(H}WSBR{QvCdPISCLIT>z9^fq%lQ#{S9C`PtXG+)wSw%h@<1 zr#H`cVB06dHY0UFWiS7^q$ zHMUJh#03j_SzNTO?sZpqt{D0Y>)p2nlrR7k%MCZXfPNCv&Im5wnotdFm$pu$*w|!D z_uo+g1sc_(yps zzn5r1xo68D# zSa<0?Igo$~;GPjvxQp2cK6q2wmT&o>vOvQ%XHiTF{R04^{X>UyYXPP`!|1?t!^Btu zZ)V|slhB$4fXqG2)Be$>xPc0akr#qZJCRV)Oysv<8$(tfigB%|e*g+xN!tpr(2?)G zut1Y>uinM^;N;s)?07g<0#gTI?tqve_i||Fp^pZ3f|U{hgd-SOk#_=|W~YhUX^@QC zKSte+M?thrxBwSRjpPC#);;bmN7?d~6JVxzv;+Kv4c0n_dIeA&aB6oJR)b3Q7TgJP z{mc+MOfIY$$)ba{U|*+*0UY{|Yu}tj_KQ3~-Iz+!xEH{b1rZ|zkDi;vib{+@2yhPX z^GHmc7tseNPM9x!2t;QV!f*1e6IC-Xr@5H3iV`-UCRQRYD~C^gkHpij(yAeWbjn*B?F0E z+E5`dZJ#1b+0YO)Sg)6>+;161O4))ugnGaAs=Yb+a z-jSZL{(UFn=?5039Y*a%d#c@5C~g*hC8*WW9(3XK!M$fOsHS)zK0kz07jM1^ z8LCwtU;O_8Qdw=n;cyle`W_b z3Q8isF-XK+%#HaXxY@=5o^O(aGeyiP_)Q07pC&STp!VWD@Y~4QoyBLSlt{vi2B3Ek zRK0M$yR=l3*(dn(&~hBAE#aWWK!Z{Z!UcDzV_*u}aU043*fg1+P=y@NqcWvT)X0HH z!v_*CqqCcZ(%Wq;=Qky4YAOg~`i%LXOzO*h-lJtr?PS6O78CDmH_>OE@*{K-A~*BS z;$E={@F1P9zKwb)8S5M!!LWSH@m>JkE%ob(M3v@iK}HMya%Kx1*EULkgcGZA5cyG_ zeL&CYFI*Tz>5(+c@>OjKAhV%X$SmPBncdTa8w$m;=roE(_qI7WA7K@W3v_oiY7dk2#j?+jWvM?Vc+Q8x5WHFmPEEW0$ zhuBEHx3OP*AwrpS*@!6UQp^O)TeiZQ8!3(E`c+xGN*&Avhz*UVJem7g$-OL0yt2Ux z<@BK!P3a_VsLNHTd@IBHH!qaDT*01ZUX&m&Sm0JmU$7wMw@QK!7I$Ms^@@)^KUOv? z8BmOlYwz!ZzM$!j^Lb^*WIe7-b{=yb-^mppIgWAi+>j_FJoRb*t@ zBOsYL@HP6Rcy46AJoD9Ya{8pgsKxpu<~}YhiCb2#4rDJvlv+I~xK0tlD|f5V!V8RB zlA%J-70Hxhw5LE$KWs}9JancJn8X!0HXp?YYjFg0PSZQ_lm`a?k_3;9%w**X1t+IJ zLJ!Eihz933kRqpSx|@;+RF;)MTd+WI^i=Fe56)zWED|A_I;cYr00)|P=WzhiPYs`xtaoMJxnSV15Pxz{RVz4fRWb7cBzUbnBKe%N3Ws5pFj)$!&a)Q zFVy_CYh2BH6;STd(=RWNkjpN6m0R=TxH4Y9`kFf+o|I>g7#uVTSAJ#xTA=?7>e&a7 z@|jPq&>Dv{LF#xxU|z$t?PupFXNRAh_Q@UCqXqXbJToW0I(yn59v(gGKkb%R7bTKG zCt!|bUnYywL!g3)nE?>_4|-m2;o{7oo8$m7%7wmDHb49w_KjEu%juH+WX|Pf_av$V z$8TKep4cFN9r-0ntkq*Ba-(uo-x-E1x z`0CU8d0Hk*N*&U#;ExkKv8Qz7ni8_&{JeaHARQfM%-vO`lx2d1({rV{-ph3cI*GIfs*) z&-#}qLtO<|qGZe{-s40}7HpOIMB=h$7oQn|7WMnK=w%9`uDw(_vXfilAA_o}E53Ml zP;Iw7)pfP9iRKE>{BSiNOF#G`i%VZmor#`x%4ChWKG}?aY`YM~J!}h}^tHs{(eUK_ ztaEbQIX;KjW=DQMJ0Eh|LC!LjjB$&ysBYtG3VrAOC3HAY4_v2Kw}jKupX(*b zcb0EOH}oo7@JSH=q3ztVqtUj?$0av2JiG=CB`c88UFqv|0huo+&uE-q{wcW#bM=eM z1Xk%>)c+62)w5SPZiC!?!ZAeIx0d~X&pXS+|DW~BG8I|Hu)~!sU$W@q64$@V>SM z-C)|e=bjhVXmsaY6jOKJ3A;4rGyui$=C}f27!s|bGcQ6Koy4|?W{sdR{yTvKvC2WD zKBd@TCQD3=Qm&F7?s8xi5(1a4jISfUkd zzy5l6YkRvDe}j+D8#N8b)Gny@GscC~ET8f2*6U&m*?m%NzD*MYx$?)Fq4{6Z@`^o5 zkw#taVTxms|3kGXhSK1Jt=$bmx1-tZuJ__M_}$*xq}e7+`K{}E_?t?@_d?_wIn9*B zo1ljDIsqgCVbSCVFXUC($zwUc7Vkq262+tC-8h05S5$XkJKE#Z&I3d^zQ&t_3tS9c zK)?KPqwr3nD;P+^%z1)L?G$&>GFdLeQe0S#%idMYP-gBn1&HNxZt2C6T@`j z?2ZM~vU*sv5+!e%I}5f-KvT~hVA^vqS#MF@dU!b8;mPWIXxF_bYT5&&W$`82Z@?kY zz0D`|^v^v`x$WaL+5>$;XJw8&pC*yZym+-@iZ-hza&`1EsF%7rTCoSB%C6Q)(Odya zdYIk`mk*wKhB0T=(144%&yI}4r%#Q;v!}*!e|VI6{odO47%WC*?GaE4+atjKbM0|o zw?|C|Irg}h*yG+ywnwN*0eb|fe~vvuWsBM)fR?dG0AI@<2VZ^ivg{Eq3)tHeX6ViA zamIK*A2!bdL5=qI3M)W#LpO$blLub_Kivj+!^ z{UK(21m@X>J?&~1w<`Hu>wfOoV>@KaJ#^Z{c+aO!s#_#DdjtG|~)%Ou#*)Qxi2anvXTxSp>F90qXjzB%?biT44 zCEYO8qm~ws6)4^obPq!41V*$)3)H)6uMk^QXn%5_!VgAA{LC_EHl2Pi- zq1O`z&~vuLoHqaOMi7)Z^*rcD#II4_8~4enfP3IRiJidg>GM|XHVVqeZ z+%;wx(Gg+oYV^73o3r#uQpA5%B#0Nj1^b5#qy5hI-u7;a3h$R?s6;yPPFeY6Gu~$s zUxM{ccMskk7AJUUH@UURpjN%MLhL+!dD@G2^DTd+@6w~mf)#HjWV+_dN_sO%s=P0& z-!AC!KhL${gXwsps?Al|T?c5h3;$;apb%g&~> zuhB`SoesOeJm2%u0x7krOZXlY@#XrSHC&HcP0jUWLrK@OH2BeBYjr+l+>d7bIgSVj z*T#e#!xd!bQ5x|%kaKwS)cE@FvH(+&2G-OelxL?jLyvS4#7w#Se^O6qV07hJ+8Y`L z9^c5vXU3rL<0HWR7hjzYPZEL#Xm`J-Cm$c44*I>;Ypqyl zIvQo?VJ7nld|*F5hJzc1u4nZ2n9mQuYtKp%T>3Go7(RYYiU5oxRq6Qk{P?t6spr{A zJ3sw`UOKy!Pq44nXo;h>6CcRPln9O2$_XVx(d8mDG|?y^>q>`guDpNx|npB>T>$DKLmCm`RU(}biKf_ta(u}B?zjFWU?wC z9iX~&&JNGc2dDl1MH$f~Naf@*c06Fdv~(CPM@E#nT2cg7hrEu!em<`zH9}oac9BJt zlU#(P%S~qKQqzIfm04s@ z^X@#xyt5wnr)AkcEzdu_$X%3w0#^CwB%ObmS)G4+^1BTGgiwxu^xV^;{1dPi#X^$K zzs#)8KYI1!GW-)lIsT_u$D;fbu*yFt>HN#g>ii!gKV|qQgmV1fgq|A|<)466{y9nK zUuIV4|Je{Gb;|Hh2<7;9L+_?A{{*b^Pf0reGII_7&xYsEO7V{fCHcoDD(wFVSZ{yl zvG!lX|6y~M@_&d>(*I!-73QCS_4aojYyUO)$L1`>KO&Ume>Mt2?`~Y!1Y&qq3Q?+R z2zve+w(!L#gW>r%N2Sam!YOGHP|eVrjS5R7hF2vLrK%Fq^Vg6FFa}$MJ}D&;iIXFd za_`J9Nsd4bZ*I9oWhXII>B)3Wei}q|3G$Qk=NJ96GBT7{<@Abc3`6Ch@JK6#qRA)D z&;+D`tTFatUSW7WC^Z6;XeGyCROwRE$&kyV5?NCgrKM1gf5#q`HzJ9o*%4%|HYEV6 z!J$RipjF6qCA~t#LYlS4jSKy=!!P>7^Yhd5 zvrqLswz;5r_eSAsRECA`G=!e#cy7gKDr?wYD-R1;zVCW?P(Z&g{?>FBmgp(0mDzy0 z`aU8}Aab{9E=Yy_rZsIV&90BO@h%TeKdqAoT5T6&x|y=$#*1glxFvdYRf!vRxUF0%@)4^nto!jcs8$8DxK=x8{0E=Z-sHVGCILW+7 zAtfHsKKttQbXzR{Eq4&5pe?4#)l5-?_&ZplrkRpfE|`A0BnPyh9me}o;A}5+N5|(` z##diy(&~$qyN=Q06FZ{^^h}1o+VIoRD~vx4Tk#I&f4u`pizv$p?EV?vAYBQ~BV

H@ud&;s5e4PMY@V@rK@J{W%T9rn}4Wl1klp;YN9ikDwp?#tF6+LP5T0)SR{ z1^}sa?5q}tP|S`W0({L-%~-fLxP|OE+P{VNim=*)?*Cz7{NtTzvj19>+R9`P2xk5MOJ6{J=_{w|_-> zu^sR*s5j<5)Z$*AetAvw@x0wK0e@&n~<1UYOk3>ZbBoSTHHX3!19F`Kdu8Q z+{7$yfmFJU=&n2_UmRY-{U?_VkPAXiY3 zvJ*GkMvAi3;yf`vjt+>0uk@s6xWr@RSnrZIMa4dRjwXNNCwMh+Hsp1j0Gg`!MkYTE z#iV6=EQk^Z`4Vp^sc3FcX2pg=`dy_MR~r?%asWiG4*o1Zc_am(GYZ-BFx}Lt+OBeI z>v^%itdZ)f|6G@*o2kZIo_pimdYqi3mE-Cd;Lmh; z${BLKcv!|rDMY&cl}Fy#TF1T@1W{-XF5@7H_U=rdZyjtvSbDHo+(~_NczFgVtq;IP z(Faih0!i|%I~>1R6Sh?x5{l5b=Z+O-AOBvH;69uRS6HHvMXYDb64IneTFWh|0OoZv z*go*Ps<(Z`fUdxp*{%UD46VPn+x?)s+jyn0loKB>`xLyo$P9&JnNTp(1t+##lHOfZ zCZ%*KFlJD~)=tL^3BLnaOtq6sDHcm{{$pc-#$47LNRqX}rmI5tF(U+es#U!b-&gUP zI6`5f#avjx>TN_| zPuOMwFUkR&_}M#PI(1Dur@5Y%w8bg<%d#VL5-pZV>fq*6EGX~D#s(CdMpVOSV6N{` zMs$6HGHL-{b7M^aPe8E00I|4-QR15~SG=1I0E(WfrupU2IO6v@q{~D*K-*68dTF=@ zc+i!xv=BKU6eV0CM41;2u2jRa?(HB9-~%mPcc>8qan<}XJi@tgZKaS=(cBu`d>ZNCz)KpYu*46$IwBg?&FaRM+vYG3M|g zEfgaQH(&%1`>?7gRb-85yt3T?Uzp<;=5_KS@62++tlLXf+@yEqDe9hCA#~s>?MCCs za|3$7BB~G`<{!1K+xgaILO7OfAAI!+XZ8GQ2zsO8bZiU ze40?G+kqT+V)~OP=I=HdhYr0B9zta0JZvKYF*6@Tz|#bo1qCAMSQ4S+<6S9#83kYj5Dd4HIOA{`T4gF9mqG0GWc`hPuJZ z-Ax$I4|aA^l&3xvX$3DrZ{GF%>z$9NENCU^Fj`s(in=B<7_Z1UY-2exqfCCYTp4l4hgr#QE+1Wa(k zzgM<4%Uz9^%y69ABb=#_cNCAkxdl$wacG1EKHdht=H}R9n}foyp0AuYsZ15DIQ{0= z%!Ij@WX7Vk-+jBg--=Rw>(=Jvz3y9Yz4czJq5L=@t|#-fiMhC^X+uuy1~*L{IDY~i zP~e!sjXiz9-UTL@O`L^?(xAc2P+(60T?$khQo%y0?zRi46K?^Q*!g+kL398x(ChNN z`^2C$d~+ZOd#zySs{MWQ`Nq}N4_BKzS65eiJJ&5Ndw?_cW`Ga$+*;dWveWuNI9;+?DNRe1&4nUWl8Wuc-f!PM0D=%n>tVOcwz!Qg0fz%{xH}wx!{IIHOa|a{ zFAxQ{=Zs@AD=$Fw_@L`_?D=5Zp_aw*fZ@t)YP~)*-B?tiCVmg8asitb z%N8Pb%S&^cqo2~ajy1afma8RYe{3^F`0h~ zx=Si4|H8S7DYQJO2tly60^!lE)$vdOdroXEsy!z`Kc9oQSi6m`GfS(L%vYR#Zqml( zF;;0xdPsHgutP4MJ;LZh@_z6s{OB?TSl`R+cv+CrZ^kZ$+6Ud)su(!1soYR53_G1S za@w<)a6Iuby&Cn|Cp+8s1{l9dG^#sa4 zce~8t;G@RGX?ikGA{a9mJrRzR(KyL#fO#?8dQyC}x4YQku>JvTZ2NcOwln>weLC%@ z4e0fGtA`WDs#p{2Vgoj+H^m?6WHnd0wUmCw)(5`+ZZR|;R^ktjlLj!hiR4q$-+uc` z#!C-Uxaj9hm0MyQ#BQQfwr&{6a9;ot8_o)f?l!HCIs->(q=PUV0bCT0&(70R@oFrv zfPlpa;Uu!SFd{gQzkc)T1-ec)5B87V{%4QH(OUx05$Vq07Y@=Lj?INIXl0yrQ(gJ9 zZc%d3uCZA7ej^MiOm<^e9qv#AA(nr(I-+*$`fd-}3;z%3cg*Wq?Dk~YY%OvjF;R0< z?Y{B05Ng^6l+=C`y02!*0+x9KIw&m&DM@F=l-ZTlwe^ihn}2-#t@zGLdDshpQ2bII z3b`UQ&Q}JI`7Mhf8IG9N!%xCYHOnyGQ7PKMH{BDEBfk5t0AP}c1CfUt0*1nJBbol1jfFA<6 z4xP*9%8jux3+pH>1&T|=A!zAnS)gzNJJPD=qw9`@ABLIf;M7eLHxf$KO<^ttW45A` zwz493F1anMD~;OP&#SO+h>N)x4JI#u83uPPhB5CwBi4U&nenQCQr z{>|`<$nuxSjE%?+TRIzaN0xHJl2#?w5r(TX{}iabGXFC}m*-DigAi9d?ufJxszTll z(_3M<9w&usZY653gxq-H^Z^Fpou0f=$R^F2d^Q^i0xQnt<_3u-#fmx60lBF(X1#}B z9ZD8WSFFbEpWnCJ*4?e90Y1*3w~O*Hw^}~WU%c6Sy_oF-s90+`r;T0}?1d%7C7RD= z%B1puB8+~r`i`Yak|YxPya7R=c@u(?za%4K0;D~TqxR+KY@-d!{`)g9Xk_ovx*#&% zgMC4GX0tE|ba5Mlis!5hN}bux;9loS8(;r-tqtnlRFgx}g#P>wnHtoeU*Fg$=CC5+ z`yVkms4u^U(Lso3H#FAkk5*}8blh}I|0q<;`a3AybNgjYL6mCWVL?vsH zPznwPK_gu%xt~%mzq4T6^!vAY`T>OP_h<61^~f~Ftn67|G)9d33KIppLF<)X;LGgiK~h?5SOHscWtNGu2e z6<3rysX^661Yx%(u;&tBg1)GBS5_ZYPt;E0JUC<_)DvmHv<)LWvrRH9oYOe;$B9eB zK)cMv*DL5Ja?wh0eK;a%AOGC`fdAm2q}6S;tEn2_ae^@LdXDe?6SX5_#`dAP=l2;- zcSY_7s|H%vf^7C`{ChkO`F;EMXH|A%QPcTk0c8P0QrbQkR$$KwE zYZOqkg%z87cNrad!0U~J-HvVx12Oq6OYzMV_7Wf*h@ zu{wFA1g2+-Bt)wU+JQLI>u+AHm;w4$?Tg64NfNcVUTZ8XOk^lJqY;W!;$Mk49LnSN zAc;}?Fe(uSkm<1gYkq2J0~C!W%H;(S&Aw0{mTPO)-~*2fXe6EBtMY0|Wc1sD3fQjx zlRhmJo}v*hj>yfUN@r=$p6^yc${!R7-|uj;)^_9rlvnyGEkNR$FTql-4P8=hMV!Md zn;S^r+IcU}$r}w++9Z$R@(h^oa=Gdtx5WfW3oDSBeBq#1xe4KR``GW_x*0dS9jo+~ zk{AH^2qRI0X4FA!rYqXAa(VTqbstGCbJ&7GDIS)Jv49kJxlo3=O>s_eS>&MQWl~lw zUqa+MLuM~cf+hJus4o;Qw%*9$%yDZDA{~M3q@4%5>y{?GY~K{{_wcBRclW@gKu#r- z&G+I2xg!`Bys5nak`lgReem*dF`hDX$jif2hfLK{sJe~%J6Jxe_=2IGgf?}wlMh1? z46VuPO$bs5QaPie3&-Z5MTTx=K}BYQ;CcogPyPrFTLb_>^S=ozErEILi9(A)(Biz; zi*aqzT5dS(glEC?gFk1%he@#aP~#wKASe8&seTTw4%=qhCZg9OWW zuP-nhO%L6xeDJJgWvI#0d^WKJlCA|+=m9Cm2aPnJb>u#yC43;t3O$DXA+sbeEL;~< zWkIg8Ge}Q9-~zcujixn92;D5kQC{tcs?Ai)RSQvEkd;jyk#!>;@&=<`HVvJmcTTer zVM@2v0WuDi1xVoU5SjUWsVNAxej`eoFxnc}_4=^7167B{#d5%U(!|m z@o)rsr!}d3cYiv3{cQhbHtx}ElR$d*HB+o2^Gry#1`41lC7Srv(nk)rL;%TEA=gF= zg##%@^(DmyL4!q(&^^ra=2$~+zLri3HGRR-;z|}ie!Tk;N~pjHVBeF?!l zSh1;=F6CQaDPoShtR^K2lj$|;UwvK4Cp`Hs<&Kh!fJJ43k))%n@@Ldzz-u$;u)8R& zFHlPn#qLp8X?$fG%N!$B;;Z(WuDvEG_vIj^XmC? z+A}l8B8SR28WSQ{;)$6rTWg40KZ<<;X!3z>g{aXz zBQDsrx{7d2ELJ!yZf@5ig4EMORwfgDma=hn>uJDZora}nsPW~YfRkdYAW$zR=UagV zioq>xmDvKr`DXD(@?{v^784ERVmh-rA7)qgF6sKX-)a~`Q=KTKMN|tz;h-NLDFcti zBjs<)4+7vtfhi? zn1PG0px?t>yDTRRYU*Sa`D{H4Kcw9jQc2+Z<_*U~;k&_ELjJfQoFy_?;?5}YOq4$ECBnw)Xh( z7Nc8T`;j)gPf^Q7-r0Ggyj0*X9DAiS{VC|X>@o7gIO=C9>yZJag3w^)L<)ew{-}ln z4A6DxB{HJNbS~p^Di8u+WhTvr!zY@n!ihD~3)l^gLlcKaZ!wH)NB&T$35hRn2%Hw=cB87%tU>J=*P$*?B$T* zY;hI=D&&VSfG&HE?_a5IzYC+-T}IaHxq{k&E=}DL_A*oc1_g6K)ih0Ui-2A{&oE}0YK;sCtwqj?5H1lFW=IDqt>7yg`WB$ zs!4C?l21QKHX0k)sG&OyqpNx9bB5lT6UNypw=wC}ksOHr$M{^coa8D2Llwn9Ne_lE z%PL19s18k9Y#&kA(X=&2h^RGBdjmH)jr%Ad7@|gg#AmJL$G#IuN$N+=8Q3}gRob_= z*oku|2DN~9VB|z9eB2N#-5o(VKm#It9j=`>?hcFUthn4r^ zBnywL;g4YIwLrrF5c?duzQ#_6t#j7^WoD=)c5g+q`RLL5CLB$UV_FvU-GPIeADEjs zAE*?Y9`oCHjMImIB6bEY%w_+i9g^~PViXRsRG2BcZLx8(aN&knKheCx8rr)|$N!xx z@GzD{mt&Q#ZLY0uY!H{8J5j$E_VM-salY9fQS*Tvu=n-bX0vZMH&-5KS`fx-8SZm4 z5@bj*D2rD|?WuBLAReTMccYg00cLTr_wl2P-4L&RH;&y%Dz6w1zfr|I#15`6V9xh? zs5b&k=8#U~NGV&kLNX$MfhH4ei}gL?3L7}e=E)9VR-yfTlHC&fY7UmTpdLiV7Ku?k zv?@eR9P2n&c-l9j@N*YRpFF3HXS(way>a3&$a3Yamc{1!;|<1AD!SZrL$-KZWCB7o ze?gegFppB^=CWwMpEjg=K$2=bwXxW>|tK5fD$ zN`lx*;|s-oA6W%-PUxz}_L~>>;r4scc9UKkd)V#`TK#sMj04w*agskDm58ia^bsu` zR0*|_6t`QA;|JnHyIq}8A+4|dar1GGRJW4oq;}>e*fG^rbdndh^{WuiY`vUGn=Mux z^jVHb4>6pbVYxXt4JRNKr`{PF;HNGqYZvF?euxL`$vHr=PV-n~*p3maKMF>nZFNJ; zAlHdh37P@&u`$GBk?{pG)=EqIbLL~-zy9cly@Lbr)S$o3rOz_bBY$m^AfDgcr0w1x z7`DE{p{_WnP}2*Rq2pEGr$rQW;z}8xY-|#}QdH(DlifHx>2rAQ_yc9f31^ z?w_vy5tmu*HF5Y%4|(<`o5&8Or?}I@>whPA8Dg|6{VQHD5=9v>wFAcqhW$+EfYuB$ zV^G5qPlVNKs1T^RcBakPW<$k03%r2`1D2>segI<}M(Kia=bLYY+_sFA=?zT}gADJ) zF-DPdhT)if&Cv?-(96s5_0myE;|Rfdb7RP}tELV6lx3+{+>8qUpflDE zTnOyJ+IwK#(D%c?cC6ti{rwFbP((xgey3ee_$77R7&ksBh;7VX((jM<(R>3gANP`3 z_C#mKH5u70y3$Ys*Ga}e)yie;*@O*!rE9_lg3%#=$8y@I?VeQ;>HWnt@8QEn`(`~ib^5&mZ6$us7NM)(vu<4Sm)JhVwG+#*XyF`{vy^i zm}=I;6!ncoFpsLDo>Qh!3=8S*Ub%DZkEYC@md`P~k%J^(=&b7YLGD`Lbh_5UJi^5d zw(t{fw2ewD=ra=x!mxAdL|bUI;}>!2{BujlW0+OIv9y+Tkp>9dbB7WDC+a*xWdkr# z;ex|3fh9K>`F!p!sm7Y99d7R*bT(I1FfROBM~`Ip(o1r@lfCRk@E!WiN=&D6K#epu z>_aBc9&9%6@1S4q_R-G%zP$WE&3u2IMB=@uc2`$c<Lbh`5c~%aG`TdeVcZv^Ws|6(FMvA8BaXTOW#Yf8zLas7OAs8*5)~fo(K!94t0? zaYq+MDmDCyo7th5kKB8iilq?lVttJZvz4K%Qv2QY`Ehg6QtaIR5Ea>lhr8BbcY!4) z8i98?e`Qdpq$c9O^tgYYKIjYtzPXuHaHJ!r3*DVG8FE{En+U19iaaF2dX*6H?GG_JrHbdKZ<7Y8eEyC2PHlylY zymL%+xuGZl;{IjZQ3xpoAd`YzZed&wOIVFMU#b;ZJeC1&rL4(`$Omz!3d3L^ZGz#% zZd586#w4z0AKB}M(J>p;C;Ppl)r4GX=G9|6V6kE6e@ih5-r~{ z83jBoCxz**o4t|S3(o?KQP_8JXWtDH^skPb$a80S`RJD763*c=rp;P z>!-xR0389f$Ey+j0#MNL0@LLxrBn||1esMlaIK1F)5t+a)XuaBcOu(Fps{>j4a%mk ztM&MJJq^ndxww}C8R&z7MX5GCb+;jd(7<1_R?Jn5AB4;<+)5%GOEtBY^YDyh=nzXF zfHEtngr>SUK91Zo_wvIBqofhZ7@^s{pXo$F(*O;HkU>Q@3WI*E+|!rLL6;T`2ZSB^vE0v2@|c%o@Y zZto3#qN+g`YnHK~cD1>1f`t7BVWe7>{5sw7E{`{w-*R}-TUb)n$!9&4Q#Xv~EfV*= z2%>#lgmr-zY0(@=w*K5V0><8~_P%q>QUGQ~%%?2nBrk7axKj~M+`k>Ew>JjM+ ziL=w-=gY^N0%MBe=BPJBiM*z?-GhVjo=!HbDqC;v#c(H{AyXV4{q3lI=mjs{@k@y$ zOrMk~Ne!y1%NX?hDS6-*6T$318UO5ZegP(u8?mhNxg(ILDkqcbGGQAB=qn4Ld_#(B zUgq}-E}bFFgQ-stM{eZ_w3$x%t>Q-U_H!)w;w3c-{YHI1yx{2jJRJieCPLfPsJ$gu z=sLn;gfu-8TeU^`ne)Ak`aI(P>&K2SWszC1SZy>UXR?S6AhbCSM>oeC)$gDrDR%YxAc0=Eph|Zl+ z9QLmo^C??>6~nl7p&u@>ZP2Z@4fzzsdQUV}2xpa5a;-HpgY-sYb(Z2afHe_6v)M~I zYZ)Fa{IX<^LQubgNgw3~@&L$*={ib`e)!rQ_5d#hsYsKjA>B@4Z@qDlcs{c+{NM9k znhC}uEIS96)}8~EpcU7$HP^dDs^|Vyz3m;Z!;Ax+s-a%N?Tz}=zKhC_-g52>o_>_M zfCE>`t;VdA1I*1j>`p?3GP6&sagx8CuZ4S7=13(4uJ6ssQ*cuFaqcps@#X4DYi$KN zk-n?~h8gKp#A=?ixd9mF8ReLa2mR|B*t@B})`ek72sRDG{x-w`tV|iIbda!X>ucIl zki!IB9yyJBY4NdWW>V@kw1w(VYvTCe5X_PG$P@iG)^h}YZAH~U9Bg35MV z^k??YjhwX=dvinf&ey%WYqw;xvaPC52-fVa%(adLgxOHuJ0h8uv%_m}ed60iu{e#w zk8Xg|!af6v_15Jwtz@b(=&&ns-EBE!6kXdRuLoa9b4{5pD14!y{t{d^<{Nfo8a?iMhx%kj4mizK0ax)BsBS}*Z>>XV!$g6tpMDt0uoGbtM$o6Z z=Euc0JH%n8jQFbz<38IAUuj%ykEVpNq*1vf(NAVhhkgdl`7fvHj93*4IW8)&>qgxB{*38d47UR_i9W)S^M zvJSqG0tGZD2eILIr;?Yos>kD&nfDOjCuU;K2b|hv{Tw>Cs z&ezgOp}x8@6 zX&UGb3g^qzFGPlW)G``hnXWMjuS$H?JJa>f1m(UsWiugCWi7AF!Z0&S#)J!1nG)jM z-%J(dU8r>3rVEu!{^~+i>O!SyWKuHYLZv~9l>Vd(l}ttfPs>SRy7PruCyv9O=OiwM zk4i((L9vhXxKho6rOcy>SKa_-52A2rV@J${V;lnD^D}EHOKoM*juxAVDLSj5b#$hW{?6C6qS!m=ON@ zMkG?g=)?4vjwabW!O?@%B7O7!{E*ST=oCg(qFGYvE4Z&(W`@P>_M0#Fy&_UE`34s) zXYZzN6poTb>~Exc@_m}+MIwYU7r5JRzOHS{*0xNZlyv$9A`FiQIZkvVKiYI5zSE1w zaGrLTz)mFR?8zL7@1O4+X-or|XU z)1U0^oxNAj#do=fdD;z%ZK}ar_>eBSpH*-bDQdu1$i%pKiri!z1@OjC<)*?Iu{TZ+ zbzAT9(oUi)b>T%nPM_%!4MD*JI@#xP{5aA6rcQ)7J5`vR#gZCdT-~SOj`%)X6i25j z%YTOdieA_0S|!8ZwU*L4yB0=7H6H2FnRT&78QAqWaguS|S$bNTSq*pLdH)UotHR7v ztV}Y=0J8#Z;NEB@q5(MA;EH~zdM`i^X8fudao~79zU~l$O%k2~Rvl0W-l?X@l0`#e z61no=e}$M2is=}*DIJCS$&1(bGLtmW#D@t=HcSH2B&k3m*LVr4ko=Q^dZ*0<-G!V2 z&jFw@#NPt zD>lO>Mx@D{tD~b}zD@$UNgzk7GDiGzW(3*LrCi%9 z1#EGbDS$ELG!`fS`ilQH8?%V#6E%dgh0`?7;tJ-A)F(uO`_n2KU5RcnNUq?&>Y1r} z#-!Vqrd&)xDrt6Q22Pn-ASNu%5~ahLzm@9A*_^s+)9B>XuU2Q?>dcbIAfaJ*N`M00 zK52P!Dv2|HOl?niThmS4Xb99&!HBRE&>I(h7el|_jFT&VC@=APYR42bI%L`M8wF{e zJO^0<0FX}nL$R5uzzE3T1%S)m1C9d&v{EufmtQT*-d`4?sD2<` zQS!gK61`|9u!m2h#I3Wmv)*0Mmf@6xpQA0|(@EvHc;xf6FhhF#A>8=NVsv??2c50h zP>2~|gD~aT8Gk5t8x-3~-=3prHMsTe4Lp2{o!+L~X;mzS_At63QMEr@6@kc<&9~kL2#;k%$f$>YN82wPXs=5P>q8{y_xq(xok|4wbU(8Bqko*6iv`**MucM^1#}{_;?8Y;;Dul+uc?^5*TO z#c`E-Fki)Vx6<)#?x8*MMhl%IQ>Y6!=D=jJ6R4MQ)4+&fgpU@c&sxLi4crTmAoTQAZr8(|J z-YJp|h{TfGkBF(x!B;=Thv( zzQ@m3al>~A>&Qtu)o$(B-fsTgY5wzr`arj(yLGB$mt3wT5t>pqdTEf$xK$Xtkc8f7 zH?|qI(`=65y685PeX)P^_MIw!PQh2Q=7A9k0s|4H%G^MtiKhcAP=uF!T$dt>Gkh2i ziXi@?L3Gdr6Kwa5hEQ=4Ob|^Y<5}WTkeLE2Oj2{Ak_q(BUmm^vi2+z4v$DjOVk1{t zC@)_Agn{~q#-t%V5F&c}&WZXHtjqrODE`gAYPb3ZprBYHRZ@!2p6^x*NBs>Ad$uWW z!B&qkyqf^_mNST(R*KpU@FyYb-Vq4d4qgrLLF90vK@mOz;Z-6nYHmDgf!Gt*)cIOP z-$@(+ouMu$nbLO>{HtZa!jTg>)Y+LE;M4xX89|+(d0Lec}KQI|qYxS-6sH)(WB!LRVKQ8FcaNGSdr*gx8>ddPEXO`5|LV#uxyJq0RVHBwV7Cef+w?O z;$U5p6oEFJDA!4?r50+o!X0O9E~C zaY$iX@wsLyV%r0-a(a&MD;39v!Qs(g0c4rW@qH?O+?)sKdjS`ps4f-Try!)$`}#=x>M5;8xb#?Pmvj?a$E18a=Ci z4z#a>UiaO^r7y?chiu^^MylS-ZZ#g_<37E()u@fU-bW-)z;2nf=xx2XOBHc@;YMZjAFF%VBh*Ln;81iGT_!oMtvc;tIY4N-txEQ@yc z`nnsn>sx{|oa40*AUO3*k@$G^!@t@;AAkS!Lz^q1q-FZOMQxmfMqyD^5p1&DwZ89K zPz@tU7{T~7PNEup;bEy^$$I@JMOPJ=()l?fg=#}*26i)bc&l;zKz!)dlr~j=L5E@n z{%d6FSz`6E#7b|ey(HBFDO9!5~Gd|xG)pesPK<+^A+gkl|rkYOG zscsp#>RarRTU)8aZkOr>>D-0fU!9)v-z{?4)VaT@&!#aayu`b|(Ur0Oms*-tZ-9=5 zopg+YA*3!$kC%sq&Y9h7aXVXEqWhg#qNWrO@;=c1rX!F(wcU(`#r0c;x2$^GJxahz z!bubtT<})F;0nGYpxokUX=i2xPLYXgDj>c~Q{F1CW_k->C#Rnn6YD^BW7a_0H#cqH zA=(n?9i2Y*5C_f~Mn#5sKFdXrMX};_Q)R@(YF6Txs=DnuR+egWt_+Lo?S)7^Xb`=_v@bW?RFJWqA!8|JuB$Yn`(dh&W^N^G7A5ZjRUNcl!`) z6<;CON%qd)UO=*KQ?dzZzuVcXW1Duj-)_r*?`$ezzv-^(k7hICC{g{rmlDoW9sWfQWw-yW@V?q|&NKvXuhJxO)I*lD+c^ zR_>r#{cK;ssvp=kHlO3XGKHW9enW~-NiJReKa`JBhh&|}U|A-x3wTB& z&;^Q7vuo=(v$&RnI6)||kH)o>1nyxBgq zp^5M95kF+<_H9|&@dweVAlA>q`d)&5Z>(d*&2om|9E#4$tVPvdwda6;rmbkLIZ3Sv z-Mxj<*ozfo30}F`s-*nQ29p!v;Vf?f!5V0YyeuQi(+-at5jQg@K7X^f2O0LeS8smY ze)9@!_X@AGhM6>k_7jo}XcC_}!?6z>XW;LmTy@+*e+h!%tpem0=1O==765VNvqZJmZwH}` zn+-61((9{GXknWLYDS_I8gQKTAG00QcmQ7V2Eav=p8gCI9?r-xZQ!NET`C$PP27CG z8XPtegrs552~fX-J~r)g6a^Ma?$3jPXP6izrP&;qD6H)dBQB=d1f2fF6mySpF(!>i zjuCPYs=z07$II=jGc`Q!d!ozsocwJf&SbP`J4Kmw5`TgZya?N+mvz#YN%E~!uitol zQZ%vUqlYy2t}%Om%)E}(P9o$CV)|a)R#Ka)(`LaAAf6rX^htGbZxb5PT&NdLy|aHw z_;C_3q-g&VIzOY=!(x~8X?l&dvd~r@03nvl4Y2C>)e4$pxDrYO3u%j3MWn4BfBylm z(N=}dn}QWvZ~ol}LeACCE20 zquwB8;cwuQZ<1&5oltc8 zCT(h|zGcVrq>?Jbtu3mgjT`AE4jvVwLzdhfYPygCAM9VoVdC1fVP>6V&;{XjwOY?4 zAo>LaV}c};Qj*W+VHQF;-$fB{0!)tHkK%)Rpa`T-H%8{v$C$bK_cY!hszGzpQ`1R#F*MsJ3{1H~E8 zC|f9`(@|}1KtTghnK0jqq?q)xHK364bIj*7p&Jf`55=oM9PPX!AHX9w!T>psmerAu zXr4m7bhPLuVgM_b=D-DMj35hSjspqJ3YFpGaA92g`L;01^yzUR4ZDQLLM$0dqNUS zLltgVQBkzhWw}uAC#Ktpc~tlYVF^y!-c2zpI-$Lyt`?c8xFPl*3$KNtlBoBEk+lkj z4_8ApC?(lJIB!g%F7-c8^rBf<{Eu_O9ilNA!;o917sIfmY6JVS5Rli$77V=MNT;41 z)^F^CFS&pR0b6ij1b*eQSZ%F{5H$qM4qGA!Nmt-vnAHWM(b_Ge{@4X5T|G(n?yu(D zy_s{`xX3Iq@{22N{lVB1F#i|^Nt)_Ch1bd(O&%=`KE1E3TG2xc2H+Y(N1=<$*~fayOV@%@l#_1YQk6iH#>npJHW(*KklJbliMGzpKW8l0 zb+g8xLKL=%C`JjpH%*y^&2r{M+k?2w=ta|si&7EcDcnnxv0@T3yGb&e$GIwKoU@HF-6a}n zZ(Zyn_n1wGR|^ME#E7|r6jPlHRawoTQZHevC~ReNagnepv$u_}K&iMq74Ad|P*UXb zuRD8WBr|+>WR}2m;b8n*=KrOw&D8E)HeI!olLq@aA3#Btk^`_j2 zs%V}a!)n&4I#1`#( z**)0l{_Xj}JghQBO0zp7pJp6yX>{cnT_(SB#d3k}m5mEq$*4goOGsw2uM`ba{x$JO zu%yO~3A6h_q?=TgbK)Ry764jMydhT16LmDfTBHlr{k?ygXJpz5@#mjjLEk}0~fO+4C$8(~~*iKa$bx9iiXk@FmXY<2>^zTl5wO?x~QKky4jZf-noLV|r7rCDDh6@o^Sp zTD~K0GAi37M41*q77#C}>hnSkO)TGLWHzg~OB^X=FEY;-3p|pYCbPh$iLy~x{8gV% zP|2|o9|u}e7NW}7v=8yy(mKqs4q0+E^9;+70#k_npjKf3FH@~YWl~zS)v1#?ZBRVP z-I7QlO^C7Fb~pjknN!&kxIoKKT+GU7!Aqt*%(|uUBy$tt$>VGr9A_eCNP5(kJUJ<{ z(Rpe>Sw#Gx>dy^Dm|8xTB$=&ZFL9+^$X1kGTQD#&x=(hQOOr*Ua6ixnqb8GMF+LL1 zWSER6Sv!+YmOGMjj7H6!B>xPvk%Ln({;*5c)YG1BPlNP%v=$8fiHA?O=K%bYl4f-} zmu4Jm3HG^Quep^gkBfu-s;HH8@k?3KF$>;H5~kE^(hraG6HUrd>5tkme-u-S7?#rk z&SK&Vv0;uVqv+*hjmdbGVu?GGac6{c3kNnMT`I5Sr6K}TxM!ry&1?|j&_{zJ)8sVs zHjPgCd1-d$nw`ualZ%GwsiI^8{sa%o;y!M54S20%eW5S+0(~EFt7Ea@G!Gw9I z+N?e>3_auMl+!_VE;%~aMt_C^h1-wYN8cWvAE5iuZx8qHR0ni@*pvv>; zB1sG$sUcTQ{16ODT`ELJ8ke`iamlq8=*dW3d*Jx5+(F>u#VGOZc4DL?keV*ab9(*g z7H{&6J(LQ(f@Mtv1E7v2LaOy16w_7ZVQ;xWfp|~F!y6XZzX*K0jE~aUxA0a|zVclk zukH)vg;&zK)#gWc<>cYLj*4BuYp4bOJL0UV9;EXS7p1y=3&w-n!MFPN-kQn8L5|--3JqrhYUefjyVm!!kc<8M z0QN)zdBE-2?aZ{Zpm!ck4dG;$Ni=9GSTHW^paZl9Yyl-1LnSP$lnfP_d9EeXgZ;AL z?gaB#hh3*QlON2<;2WCt$tEn%*y`BkDfh`hga1i0g+Vea0?{eRWQ2w!Z#N3^RzsTRPa+#eI^F7P zjrH6*%$aoB;!4|F1uY+)Nv7G8X&EqS!#YuM@{N*_ENwH-Q8$1>6(HTc*mlvEQ{@-Z zbWun!Y{oN~n$-|S;z1&{4QK0SMOs~>9C$V3Xg8>Z9aC&Je%jdF`gt`WAP~^DJTJIu z4}EzZWU~rayLfl?_=BK#y!itP9afclMMbk#kRAYU)TS#A`&P#h_sOKTD&CTh;=RUe z5$LN{-7a1ohUPtd6`LE4_i*$ES%LLTwzTc^z2KI{gAq)tI*}TAhKh!|0p;XO!0-~M z-^g?ieDpLbk*l=0Qd(3SK&sg8_Fw(j&@roXV2Sv`=^H| zKOF5JgU^xOZ=UU+*CF}F-J15Dj_+%=51!WQ%!ChWf6^!Q{?mt>KclD3iES{#ZaJg_ zfeKy@`^a?6i=?C&y?eJQk}pJga!F0MpZta2G|-J79yEpF9oP_J9S=%mj0danoe?^p z0w&P7%s2@q2%A-|aE{Gf;lU)@hcpTM2VfTR|E?~hH6R^4R*ma8^0N9%9=bz)P?WNu zkh@GSXonZ%R|lpgl>*2EF^J>`X{M+{{a8drQdA&cym)s0q?SO4X zGy1mI?f8vrn4KomP7MXfew5LaU*yEqRAreAo@l~Q#iY+|{EQa4>vz1N?SyR!3Z-(= z8Bun^q#q(I5gRfe>)}m27An2PeM5YK&ZqYdKW`nkzYv=x4kbM#uLgwYp$|fj)27&% z?T+8&VNnc1TX(E5pj!$vva%jtRQ6k6oZyV!le@C`Q{DUe_Aiw`Ht*hk`y&y)eF1++ z>Z0=Y+vOL;bs#rAJxxou;2l71x;E;_su_1tm5LpXregX}`E!fDn6GsrC1+TiZlbmJ$3#k*&ktp@ET zhAr3o^4I&AM`$Lxzdq!>`@062?@ zFT{p9qKu-Kk2NOaRf;9V_iNP6qzQBol}f3 zOwgsrwr$(CZQHhO+qUhQcWm3XZS()K`Lo%}O)7QW7oAk6`keEWW&X1?pPZ96W?oxg z=3(Nr%*dsZLObU#0E}XOAJX&3@=Xx89zYqMFxS8J^>*O`U-{qTjW(u55vU_t*quxs z9iD@zE=zU3m(pBhhyqLe?`Zryf|-}Oh(9b-3C#%+U~1yHz)Zf)4&I-rWe5qFZb5K~Xf7m0fN&|KyS zT)x%@q5}jr5=MH%2q$hsW|*lWnXMrA(0;dKDI-{~yr54%>FNp_A}f&7d;80foepB; zcA;me5}-Ea84h|d)z9f=xxGi3rM$r7oZe$RMBb0O^D86EZ zL|B|c!-1BBOhbS8Od_he^)Qx6qloh@5QJW9Umc6V12=wk`vwe=u~Bb`k8b~YC3KWc zenkcXmfM9FEUO@jlM0O`ilE7`5>iTot2I>EI4~d6^jkvCvF5}%l)kSz!v>WPDjt*) zq4yQmpo%-M!Vw$1c(4qo+hQ~^l9M9Mgv&@sk@K61OBAW7H~)ZYl2G&FRZbDXI>DTB z^}7nOvX(y9DG-3qoX)-2@_YoK;Y1hFdym%Rbc2N1EOriFUFcwPzl5c_c4J+!|3k(M z1wz>Qh!zwo4U}D^Hq*bt!>fy$l0tpjPJ)N2S6?w%wX*!myH^h#v0<0I&(nDKR)m`} zH*tD>9*s5AZ|>drJG(hJ(RhdBY4>~2#}7Y9er+5~nBO$p^K)~H>!IRPVmv{1>v|2A z0E>`Pqzw{(CC&-6~ z)3uoDyXejp*8T|$MhR5a>FDFyv=wH@A=wfu@&ROOwrR%AnY0E`WCun)HF1a$KrbA_ zu7#hm_;9_Og}i%p3^PW`U2?>o^!f>ngZrNCcR&Q^A$N>-SW^#6GM)GJBzTB>ywsYmtYCf7L#{KHM(+YL?N5utt?XiYOr* zcO9^%Ae&!@?a<9$g!b&02FqsjxAMbWE;m|a|2cas{!GybC-XfN0yBqzRZTpcX&+{y z>uBleEIX8=6eO^c8Ug70jwXi0&UqY1rt=LVi% zq1{&fT^t(ynE&h&+AINncVgiK0gvon3=ce5`*S#S{d;itTbZD{Y*n>&zn{+KlM~oP zlk%_(1u_2A2%>R&v=Az8n*~SqJFv6$tV3OW@Byk^Mc(T|^)(0ZxlsHgdM;-Z1uWC6 z;uk*agR>zm20%!3to&>aR_k&dwnge=O^gFU+qxijn@pyXf%S}0+~mEQWQC&!kj0(9 zeLkO;RXtNaspB46xLyu|KTThaNM4HR$>62CcZo{UL`N3%E1X~U3sXbOzfJ%^+-hpF zA=@;4H0f3fk|-X47)#m6nIhDl{HG!=qoT)I@RDri>5BokO0Vlr0@p(%o0k_){-r8( zTmF$&h9)6b!yqvCMK1R>$#In#n}tx%a~dbBkH_12osATWzlEZ>v3cY@fo+2&D@E)D+}e!k|U%>ilX$I4*gLpToMA3W;E8u_&hl*Ffss?=4Hj zD5nV>d~{b~W`X&R(49LkMYvol6_jG55F#A+8ti~D{wveU4Oe%>M6btozqqrwqB;nN zauE(AC{NwEt}X~eBWFXQ&}WN z7M0}hf%@?NoJJ12wf$<-xmlri%96qaXv?dTY!IWq>ynp zDJfTjF`iZSfZJLin+vU3g9~yZnnk+#K&dL>xq(~ZtOOfyUSSbC|5&+OU5jc|n1H!cb!Ox$|6>O(X4wWr z@hd?8_ghrBb>$sbBvvA1gY#QgH9%DmTCYfT}iK+B(p1=dxXQ1<(zzh^HNkGza(_$nTm|*HyE8-K@6F z0Zc9$qJ;~$0Ar`U5 zDa=@!MV27-*2L5;sBBGYdD+DECw-FZT2<>$ba_|zU-h61$l5E>4l%N-WiQ4{;%kx0 z$0^0H67^1(5yi5ob*Q6xB~lr^TH&X_8e|vJv#LX8vp3yqyxai5-T?jCA~@qK(%7Ab zuL4fU0m&%RSQj7^Pn71|V6KmKfhQs0v8U~aI^6t##U|=T|EM7NcX>Bpv|c~c9&lpm zPnj@2EOZN+#RHJT?4`&qZBi%T6gaR%=M4bGV8xV5f0btHuc*%eU&YoIyhS64(+}J0 zyBTF;Jb+q;0~W_CdrA5AO9+Sj)>nPW9X27^sRHWD85KepPC>kB!}FReJlDl=iO-!e z;4rZ|PRZy9RJd=;hS01Lf+!vT0~5lnf?RxHd1(r}3Y&F2>1N2_{nj2TuT8klmg$5I-7bZC??E$Op}0(wN3hY>a;<>h+3PP zAh-*#*8NcJmPY%yQzdoUQBWFVsD>v{2&XuP3QNYIBLXMS_(Dar7KKZ9o!(oT%1G&o zC#FzhT`oc^EWK~Ih$MZ0cOEFyq27lP=#tjqXB+%YM^rcogS(lt2QCb6HW;yhAAurQp z`;r0Kp6+*JW1FWVx!Z1K3|rMY;6x1>a%8?ABL5mnK0OvUQR;cFN|BUUP3|RhOoLEW z(3H1guR>3bcU$6hkxY-P>VIN*p()}xMRmM{a7ids^^@90@WAN%RN=skU39jC4k$f2gI*2ozUn zKqo=OZV`cPW*XRqIbTj@HWr>vas>k{%UBk9CkkxKEtR?YZ;@hgSnQrT9$QqH$

j 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

|dpE(KM`*nQr1bSkmft1U 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
#Ov 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�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

lgtnaOYN-!okbFNLP;Ao2}8 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 z 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 for cases where addition should be performed in the absl::Time domain. When adding two values, and one is known to be an absl::Time, we can infer that the other should be interpreted as an absl::Duration of a similar scale, and make that inference explicit.

+

Examples:

+
// Original - Addition in the integer domain
+int x;
+absl::Time t;
+int result = absl::ToUnixSeconds(t) + x;
+
+// Suggestion - Addition in the absl::Time domain
+int result = absl::ToUnixSeconds(t + absl::Seconds(x));
+

(Clang-Tidy original name: abseil-duration-addition)

+ + +#### Duration Comparison {#CT_ABS_DC} +

Checks for comparisons which should be in the absl::Duration domain instead of the floating point or integer domains.

+

N.B.: In cases where a Duration was being converted to an integer and then compared against a floating-point value, truncation during the Duration conversion might yield a different result. In practice this is very rare, and still indicates a bug which should be fixed.

+

Examples:

+
// Original - Comparison in the floating point domain
+double x;
+absl::Duration d;
+if (x < absl::ToDoubleSeconds(d)) ...
+
+// Suggested - Compare in the absl::Duration domain instead
+if (absl::Seconds(x) < d) ...
+
+
+// Original - Comparison in the integer domain
+int x;
+absl::Duration d;
+if (x < absl::ToInt64Microseconds(d)) ...
+
+// Suggested - Compare in the absl::Duration domain instead
+if (absl::Microseconds(x) < d) ...
+

(Clang-Tidy original name: abseil-duration-comparison)

+ + +#### Duration Conversion Cast {#CT_ABS_DCC} +

Checks for casts of absl::Duration conversion functions, and recommends the right conversion function instead.

+

Examples:

+
// Original - Cast from a double to an integer
+absl::Duration d;
+int i = static_cast<int>(absl::ToDoubleSeconds(d));
+
+// Suggested - Use the integer conversion function directly.
+int i = absl::ToInt64Seconds(d);
+
+
+// Original - Cast from a double to an integer
+absl::Duration d;
+double x = static_cast<double>(absl::ToInt64Seconds(d));
+
+// Suggested - Use the integer conversion function directly.
+double x = absl::ToDoubleSeconds(d);
+

Note: In the second example, the suggested fix could yield a different result, as the conversion to integer could truncate. In practice, this is very rare, and you should use absl::Trunc to perform this operation explicitly instead.

+

(Clang-Tidy original name: abseil-duration-conversion-cast)

+ + +#### Duration Division {#CT_ABS_DD} +

absl::Duration arithmetic works like it does with integers. That means that division of two absl::Duration objects returns an int64 with any fractional component truncated toward 0. See this link for more information on arithmetic with absl::Duration.

+

For example:

+
absl::Duration d = absl::Seconds(3.5);
+int64 sec1 = d / absl::Seconds(1);     // Truncates toward 0.
+int64 sec2 = absl::ToInt64Seconds(d);  // Equivalent to division.
+assert(sec1 == 3 && sec2 == 3);
+
+double dsec = d / absl::Seconds(1);  // WRONG: Still truncates toward 0.
+assert(dsec == 3.0);
+

If you want floating-point division, you should use either the absl::FDivDuration() function, or one of the unit conversion functions such as absl::ToDoubleSeconds(). For example:

+
absl::Duration d = absl::Seconds(3.5);
+double dsec1 = absl::FDivDuration(d, absl::Seconds(1));  // GOOD: No truncation.
+double dsec2 = absl::ToDoubleSeconds(d);                 // GOOD: No truncation.
+assert(dsec1 == 3.5 && dsec2 == 3.5);
+

This check looks for uses of absl::Duration division that is done in a floating-point context, and recommends the use of a function that returns a floating-point value.

+

(Clang-Tidy original name: abseil-duration-division)

+ + +#### Duration Factory Float {#CT_ABS_DFF} +

Checks for cases where the floating-point overloads of various absl::Duration factory functions are called when the more-efficient integer versions could be used instead.

+

This check will not suggest fixes for literals which contain fractional floating point values or non-literals. It will suggest removing superfluous casts.

+

Examples:

+
// Original - Providing a floating-point literal.
+absl::Duration d = absl::Seconds(10.0);
+
+// Suggested - Use an integer instead.
+absl::Duration d = absl::Seconds(10);
+
+
+// Original - Explicitly casting to a floating-point type.
+absl::Duration d = absl::Seconds(static_cast<double>(10));
+
+// Suggested - Remove the explicit cast
+absl::Duration d = absl::Seconds(10);
+

(Clang-Tidy original name: abseil-duration-factory-float)

+ + +#### Duration Factory Scale {#CT_ABS_DFS} +

Checks for cases where arguments to absl::Duration factory functions are scaled internally and could be changed to a different factory function. This check also looks for arguments with a zero value and suggests using absl::ZeroDuration() instead.

+

Examples:

+
// Original - Internal multiplication.
+int x;
+absl::Duration d = absl::Seconds(60 * x);
+
+// Suggested - Use absl::Minutes instead.
+absl::Duration d = absl::Minutes(x);
+
+
+// Original - Internal division.
+int y;
+absl::Duration d = absl::Milliseconds(y / 1000.);
+
+// Suggested - Use absl:::Seconds instead.
+absl::Duration d = absl::Seconds(y);
+
+
+// Original - Zero-value argument.
+absl::Duration d = absl::Hours(0);
+
+// Suggested = Use absl::ZeroDuration instead
+absl::Duration d = absl::ZeroDuration();
+

(Clang-Tidy original name: abseil-duration-factory-scale)

+ + +#### Duration Subtraction {#CT_ABS_DS} +

Checks for cases where subtraction should be performed in the absl::Duration domain. When subtracting two values, and the first one is known to be a conversion from absl::Duration, we can infer that the second should also be interpreted as an absl::Duration, and make that inference explicit.

+

Examples:

+
// Original - Subtraction in the double domain
+double x;
+absl::Duration d;
+double result = absl::ToDoubleSeconds(d) - x;
+
+// Suggestion - Subtraction in the absl::Duration domain instead
+double result = absl::ToDoubleSeconds(d - absl::Seconds(x));
+
+// Original - Subtraction of two Durations in the double domain
+absl::Duration d1, d2;
+double result = absl::ToDoubleSeconds(d1) - absl::ToDoubleSeconds(d2);
+
+// Suggestion - Subtraction in the absl::Duration domain instead
+double result = absl::ToDoubleSeconds(d1 - d2);
+

Note: As with other clang-tidy checks, it is possible that multiple fixes may overlap (as in the case of nested expressions), so not all occurrences can be transformed in one run. In particular, this may occur for nested subtraction expressions. Running clang-tidy multiple times will find and fix these overlaps.

+

(Clang-Tidy original name: abseil-duration-subtraction)

+ + +#### Duration Unnecessary Conversion {#CT_ABS_DUC} +

Finds and fixes cases where absl::Duration values are being converted to numeric types and back again.

+

Floating-point examples:

+
// Original - Conversion to double and back again
+absl::Duration d1;
+absl::Duration d2 = absl::Seconds(absl::ToDoubleSeconds(d1));
+
+// Suggestion - Remove unnecessary conversions
+absl::Duration d2 = d1;
+
+// Original - Division to convert to double and back again
+absl::Duration d2 = absl::Seconds(absl::FDivDuration(d1, absl::Seconds(1)));
+
+// Suggestion - Remove division and conversion
+absl::Duration d2 = d1;
+

Integer examples:

+
// Original - Conversion to integer and back again
+absl::Duration d1;
+absl::Duration d2 = absl::Hours(absl::ToInt64Hours(d1));
+
+// Suggestion - Remove unnecessary conversions
+absl::Duration d2 = d1;
+
+// Original - Integer division followed by conversion
+absl::Duration d2 = absl::Seconds(d1 / absl::Seconds(1));
+
+// Suggestion - Remove division and conversion
+absl::Duration d2 = d1;
+

Unwrapping scalar operations:

+
// Original - Multiplication by a scalar
+absl::Duration d1;
+absl::Duration d2 = absl::Seconds(absl::ToInt64Seconds(d1) * 2);
+
+// Suggestion - Remove unnecessary conversion
+absl::Duration d2 = d1 * 2;
+

Note: Converting to an integer and back to an absl::Duration might be a truncating operation if the value is not aligned to the scale of conversion. In the rare case where this is the intended result, callers should use absl::Trunc to truncate explicitly.

+

(Clang-Tidy original name: abseil-duration-unnecessary-conversion)

+ + +#### Faster Strsplit Delimiter {#CT_ABS_FSD} +

Finds instances of absl::StrSplit() or absl::MaxSplits() where the delimiter is a single character string literal and replaces with a character. The check will offer a suggestion to change the string literal into a character. It will also catch code using absl::ByAnyChar() for just a single character and will transform that into a single character as well.

+

These changes will give the same result, but using characters rather than single character string literals is more efficient and readable.

+

Examples:

+
// Original - the argument is a string literal.
+for (auto piece : absl::StrSplit(str, "B")) {
+
+// Suggested - the argument is a character, which causes the more efficient
+// overload of absl::StrSplit() to be used.
+for (auto piece : absl::StrSplit(str, 'B')) {
+
+
+// Original - the argument is a string literal inside absl::ByAnyChar call.
+for (auto piece : absl::StrSplit(str, absl::ByAnyChar("B"))) {
+
+// Suggested - the argument is a character, which causes the more efficient
+// overload of absl::StrSplit() to be used and we do not need absl::ByAnyChar
+// anymore.
+for (auto piece : absl::StrSplit(str, 'B')) {
+
+
+// Original - the argument is a string literal inside absl::MaxSplits call.
+for (auto piece : absl::StrSplit(str, absl::MaxSplits("B", 1))) {
+
+// Suggested - the argument is a character, which causes the more efficient
+// overload of absl::StrSplit() to be used.
+for (auto piece : absl::StrSplit(str, absl::MaxSplits('B', 1))) {
+

(Clang-Tidy original name: abseil-faster-strsplit-delimiter)

+ + +#### No Internal Dependencies {#CT_ABS_NID} +

Warns if code using Abseil depends on internal details. If something is in a namespace that includes the word “internal”, code is not allowed to depend upon it beaucse it’s an implementation detail. They cannot friend it, include it, you mention it or refer to it in any way. Doing so violates Abseil’s compatibility guidelines and may result in breakage. See https://abseil.io/about/compatibility for more information.

+

The following cases will result in warnings:

+
absl::strings_internal::foo();
+// warning triggered on this line
+class foo {
+  friend struct absl::container_internal::faa;
+  // warning triggered on this line
+};
+absl::memory_internal::MakeUniqueResult();
+// warning triggered on this line
+

(Clang-Tidy original name: abseil-no-internal-dependencies)

+ + +#### No Namespace {#CT_ABS_NN} +

Ensures code does not open namespace absl as that violates Abseil’s compatibility guidelines. Code should not open namespace absl as that conflicts with Abseil’s compatibility guidelines and may result in breakage.

+

Any code that uses:

+
namespace absl {
+ ...
+}
+

will be prompted with a warning.

+

See the full Abseil compatibility guidelines for more information.

+

(Clang-Tidy original name: abseil-no-namespace)

+ + +#### Redundant Strcat Calls {#CT_ABS_RSC} +

Suggests removal of unnecessary calls to absl::StrCat when the result is being passed to another call to absl::StrCat or absl::StrAppend.

+

The extra calls cause unnecessary temporary strings to be constructed. Removing them makes the code smaller and faster.

+

Examples:

+
std::string s = absl::StrCat("A", absl::StrCat("B", absl::StrCat("C", "D")));
+//before
+
+std::string s = absl::StrCat("A", "B", "C", "D");
+//after
+
+absl::StrAppend(&s, absl::StrCat("E", "F", "G"));
+//before
+
+absl::StrAppend(&s, "E", "F", "G");
+//after
+

(Clang-Tidy original name: abseil-redundant-strcat-calls)

+ + +#### Str Cat Append {#CT_ABS_SCA} +

Flags uses of absl::StrCat() to append to a std::string. Suggests absl::StrAppend() should be used instead.

+

The extra calls cause unnecessary temporary strings to be constructed. Removing them makes the code smaller and faster.

+
a = absl::StrCat(a, b); // Use absl::StrAppend(&a, b) instead.
+

Does not diagnose cases where absl::StrCat() is used as a template argument for a functor.

+

(Clang-Tidy original name: abseil-str-cat-append)

+ + +#### String Find Startswith {#CT_ABS_SFS} +

Checks whether a std::string::find() result is compared with 0, and suggests replacing with absl::StartsWith(). This is both a readability and performance issue.

+
string s = "...";
+if (s.find("Hello World") == 0) { /* do something */ }
+

becomes

+
string s = "...";
+if (absl::StartsWith(s, "Hello World")) { /* do something */ }
+
Options
+

StringLikeClasses

+

Semicolon-separated list of names of string-like classes. By default only std::basic_string is considered. The list of methods to considered is fixed.

+

IncludeStyle

+

A string specifying which include-style is used, llvm or google. Default is llvm.

+

AbseilStringsMatchHeader

+

The location of Abseil’s strings/match.h. Defaults to absl/strings/match.h.

+

(Clang-Tidy original name: abseil-string-find-startswith)

+ + +#### String Find Str Contains {#CT_ABS_SFSC} +

Finds s.find(...) == string::npos comparisons (for various string-like types) and suggests replacing with absl::StrContains().

+

This improves readability and reduces the likelihood of accidentally mixing find() and npos from different string-like types.

+

By default, “string-like types” includes ::std::basic_string, ::std::basic_string_view, and ::absl::string_view. See the StringLikeClasses option to change this.

+
std::string s = "...";
+if (s.find("Hello World") == std::string::npos) { /* do something */ }
+
+absl::string_view a = "...";
+if (absl::string_view::npos != a.find("Hello World")) { /* do something */ }
+

becomes

+
std::string s = "...";
+if (!absl::StrContains(s, "Hello World")) { /* do something */ }
+
+absl::string_view a = "...";
+if (absl::StrContains(a, "Hello World")) { /* do something */ }
+
Options
+

StringLikeClasses

+

Semicolon-separated list of names of string-like classes. By default includes ::std::basic_string, ::std::basic_string_view, and ::absl::string_view.

+

IncludeStyle

+

A string specifying which include-style is used, llvm or google. Default is llvm.

+

AbseilStringsMatchHeader

+

The location of Abseil’s strings/match.h. Defaults to absl/strings/match.h.

+

(Clang-Tidy original name: abseil-string-find-str-contains)

+ + +#### Time Comparison {#CT_ABS_TC} +

Prefer comparisons in the absl::Time domain instead of the integer domain.

+

N.B.: In cases where an absl::Time is being converted to an integer, alignment may occur. If the comparison depends on this alignment, doing the comparison in the absl::Time domain may yield a different result. In practice this is very rare, and still indicates a bug which should be fixed.

+

Examples:

+
// Original - Comparison in the integer domain
+int x;
+absl::Time t;
+if (x < absl::ToUnixSeconds(t)) ...
+
+// Suggested - Compare in the absl::Time domain instead
+if (absl::FromUnixSeconds(x) < t) ...
+

(Clang-Tidy original name: abseil-time-comparison)

+ + +#### Time Subtraction {#CT_ABS_TS} +

Finds and fixes absl::Time subtraction expressions to do subtraction in the Time domain instead of the numeric domain.

+

There are two cases of Time subtraction in which deduce additional type information:

+
    +
  • When the result is an absl::Duration and the first argument is an absl::Time.
  • +
  • When the second argument is a absl::Time.
  • +
+

In the first case, we must know the result of the operation, since without that the second operand could be either an absl::Time or an absl::Duration. In the second case, the first operand must be an absl::Time, because subtracting an absl::Time from an absl::Duration is not defined.

+

Examples:

+
int x;
+absl::Time t;
+
+// Original - absl::Duration result and first operand is a absl::Time.
+absl::Duration d = absl::Seconds(absl::ToUnixSeconds(t) - x);
+
+// Suggestion - Perform subtraction in the Time domain instead.
+absl::Duration d = t - absl::FromUnixSeconds(x);
+
+
+// Original - Second operand is an absl::Time.
+int i = x - absl::ToUnixSeconds(t);
+
+// Suggestion - Perform subtraction in the Time domain instead.
+int i = absl::ToInt64Seconds(absl::FromUnixSeconds(x) - t);
+

(Clang-Tidy original name: abseil-time-subtraction)

+ + +#### Upgrade Duration Conversions {#CT_ABS_UDC} +

Finds calls to absl::Duration arithmetic operators and factories whose argument needs an explicit cast to continue compiling after upcoming API changes.

+

The operators =, /=, , and / for absl::Duration currently accept an argument of class type that is convertible to an arithmetic type. Such a call currently converts the value to an int64_t, even in a case such as std::atomic that would result in lossy conversion.

+

Additionally, the absl::Duration factory functions (absl::Hours, absl::Minutes, etc) currently accept an int64_t or a floating-point type. Similar to the arithmetic operators, calls with an argument of class type that is convertible to an arithmetic type go through the int64_t path.

+

These operators and factories will be changed to only accept arithmetic types to prevent unintended behavior. After these changes are released, passing an argument of class type will no longer compile, even if the type is implicitly convertible to an arithmetic type.

+

Here are example fixes created by this check:

+
std::atomic<int> a;
+absl::Duration d = absl::Milliseconds(a);
+d *= a;
+

becomes

+
std::atomic<int> a;
+absl::Duration d = absl::Milliseconds(static_cast<int64_t>(a));
+d *= static_cast<int64_t>(a);
+

Note that this check always adds a cast to int64_t in order to preserve the current behavior of user code. It is possible that this uncovers unintended behavior due to types implicitly convertible to a floating-point type.

+

(Clang-Tidy original name: abseil-upgrade-duration-conversions)

+ + +### Altera + +#### Kernel Name Restriction {#CT_ALT_KNR} +

Finds kernel files and include directives whose filename is kernel.cl, Verilog.cl, or VHDL.cl. The check is case insensitive.

+

Such kernel file names cause the offline compiler to generate intermediate design files that have the same names as certain internal files, which leads to a compilation error.

+

Based on the Guidelines for Naming the Kernel section in the Intel FPGA SDK for OpenCL Pro Edition: Programming Guide.

+

(Clang-Tidy original name: altera-kernel-name-restriction)

+ + +#### Single Work Item Barrier {#CT_ALT_SWIB} +

Finds OpenCL kernel functions that call a barrier function but do not call an ID function (get_local_id, get_local_id, get_group_id, or get_local_linear_id).

+

These kernels may be viable single work-item kernels, but will be forced to execute as NDRange kernels if using a newer version of the Altera Offline Compiler (>= v17.01).

+

If using an older version of the Altera Offline Compiler, these kernel functions will be treated as single work-item kernels, which could be inefficient or lead to errors if NDRange semantics were intended.

+

Based on the Altera SDK for OpenCL: Best Practices Guide.

+

Examples:

+
// error: function calls barrier but does not call an ID function.
+void __kernel barrier_no_id(__global int * foo, int size) {
+  for (int i = 0; i < 100; i++) {
+    foo[i] += 5;
+  }
+  barrier(CLK_GLOBAL_MEM_FENCE);
+}
+
+// ok: function calls barrier and an ID function.
+void __kernel barrier_with_id(__global int * foo, int size) {
+  for (int i = 0; i < 100; i++) {
+    int tid = get_global_id(0);
+    foo[tid] += 5;
+  }
+  barrier(CLK_GLOBAL_MEM_FENCE);
+}
+
+// ok with AOC Version 17.01: the reqd_work_group_size turns this into
+// an NDRange.
+__attribute__((reqd_work_group_size(2,2,2)))
+void __kernel barrier_with_id(__global int * foo, int size) {
+  for (int i = 0; i < 100; i++) {
+    foo[tid] += 5;
+  }
+  barrier(CLK_GLOBAL_MEM_FENCE);
+}
+
Options
+

AOCVersion

+

Defines the version of the Altera Offline Compiler. Defaults to 1600 (corresponding to version 16.00).

+

(Clang-Tidy original name: altera-single-work-item-barrier)

+ + +#### Struct Pack Align {#CT_ALT_SPA} +

Finds structs that are inefficiently packed or aligned, and recommends packing and/or aligning of said structs as needed.

+

Structs that are not packed take up more space than they should, and accessing structs that are not well aligned is inefficient.

+

Fix-its are provided to fix both of these issues by inserting and/or amending relevant struct attributes.

+

Based on the Altera SDK for OpenCL: Best Practices Guide.

+
// The following struct is originally aligned to 4 bytes, and thus takes up
+// 12 bytes of memory instead of 10. Packing the struct will make it use
+// only 10 bytes of memory, and aligning it to 16 bytes will make it
+// efficient to access.
+struct example {
+  char a;    // 1 byte
+  double b;  // 8 bytes
+  char c;    // 1 byte
+};
+
+// The following struct is arranged in such a way that packing is not needed.
+// However, it is aligned to 4 bytes instead of 8, and thus needs to be
+// explicitly aligned.
+struct implicitly_packed_example {
+  char a;  // 1 byte
+  char b;  // 1 byte
+  char c;  // 1 byte
+  char d;  // 1 byte
+  int e;   // 4 bytes
+};
+
+// The following struct is explicitly aligned and packed.
+struct good_example {
+  char a;    // 1 byte
+  double b;  // 8 bytes
+  char c;    // 1 byte
+} __attribute__((packed)) __attribute__((aligned(16));
+
+// Explicitly aligning a struct to the wrong value will result in a warning.
+// The following example should be aligned to 16 bytes, not 32.
+struct badly_aligned_example {
+  char a;    // 1 byte
+  double b;  // 8 bytes
+  char c;    // 1 byte
+} __attribute__((packed)) __attribute__((aligned(32)));
+

(Clang-Tidy original name: altera-struct-pack-align)

+ + +### Android + +#### Cloexec Accept {#CT_AND_CA2} +

The usage of accept() is not recommended, it’s better to use accept4(). Without this flag, an opened sensitive file descriptor would remain open across a fork+exec to a lower-privileged SELinux domain.

+

Examples:

+
accept(sockfd, addr, addrlen);
+
+// becomes
+
+accept4(sockfd, addr, addrlen, SOCK_CLOEXEC);
+

(Clang-Tidy original name: android-cloexec-accept)

+ + +#### Cloexec Accept4 {#CT_AND_CA} +

accept4() should include SOCK_CLOEXEC in its type argument to avoid the file descriptor leakage. Without this flag, an opened sensitive file would remain open across a fork+exec to a lower-privileged SELinux domain.

+

Examples:

+
accept4(sockfd, addr, addrlen, SOCK_NONBLOCK);
+
+// becomes
+
+accept4(sockfd, addr, addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
+

(Clang-Tidy original name: android-cloexec-accept4)

+ + +#### Cloexec Creat {#CT_AND_CC} +

The usage of creat() is not recommended, it’s better to use open().

+

Examples:

+
int fd = creat(path, mode);
+
+// becomes
+
+int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
+

(Clang-Tidy original name: android-cloexec-creat)

+ + +#### Cloexec Dup {#CT_AND_CD} +

The usage of dup() is not recommended, it’s better to use fcntl(), which can set the close-on-exec flag. Otherwise, an opened sensitive file would remain open across a fork+exec to a lower-privileged SELinux domain.

+

Examples:

+
int fd = dup(oldfd);
+
+// becomes
+
+int fd = fcntl(oldfd, F_DUPFD_CLOEXEC);
+

(Clang-Tidy original name: android-cloexec-dup)

+ + +#### Cloexec Epoll Create {#CT_AND_CEC2} +

The usage of epoll_create() is not recommended, it’s better to use epoll_create1(), which allows close-on-exec.

+

Examples:

+
epoll_create(size);
+
+// becomes
+
+epoll_create1(EPOLL_CLOEXEC);
+

(Clang-Tidy original name: android-cloexec-epoll-create)

+ + +#### Cloexec Epoll Create1 {#CT_AND_CEC} +

epoll_create1() should include EPOLL_CLOEXEC in its type argument to avoid the file descriptor leakage. Without this flag, an opened sensitive file would remain open across a fork+exec to a lower-privileged SELinux domain.

+

Examples:

+
epoll_create1(0);
+
+// becomes
+
+epoll_create1(EPOLL_CLOEXEC);
+

(Clang-Tidy original name: android-cloexec-epoll-create1)

+ + +#### Cloexec Fopen {#CT_AND_CF} +

fopen() should include e in their mode string; so re would be valid. This is equivalent to having set FD_CLOEXEC on that descriptor.

+

Examples:

+
fopen("fn", "r");
+
+// becomes
+
+fopen("fn", "re");
+

(Clang-Tidy original name: android-cloexec-fopen)

+ + +#### Cloexec Inotify Init {#CT_AND_CII2} +

The usage of inotify_init() is not recommended, it’s better to use inotify_init1().

+

Examples:

+
inotify_init();
+
+// becomes
+
+inotify_init1(IN_CLOEXEC);
+

(Clang-Tidy original name: android-cloexec-inotify-init)

+ + +#### Cloexec Inotify Init1 {#CT_AND_CII} +

inotify_init1() should include IN_CLOEXEC in its type argument to avoid the file descriptor leakage. Without this flag, an opened sensitive file would remain open across a fork+exec to a lower-privileged SELinux domain.

+

Examples:

+
inotify_init1(IN_NONBLOCK);
+
+// becomes
+
+inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
+

(Clang-Tidy original name: android-cloexec-inotify-init1)

+ + +#### Cloexec Memfd Create {#CT_AND_CMC} +

memfd_create() should include MFD_CLOEXEC in its type argument to avoid the file descriptor leakage. Without this flag, an opened sensitive file would remain open across a fork+exec to a lower-privileged SELinux domain.

+

Examples:

+
memfd_create(name, MFD_ALLOW_SEALING);
+
+// becomes
+
+memfd_create(name, MFD_ALLOW_SEALING | MFD_CLOEXEC);
+

(Clang-Tidy original name: android-cloexec-memfd-create)

+ + +#### Cloexec Open {#CT_AND_CO} +

A common source of security bugs is code that opens a file without using the O_CLOEXEC flag. Without that flag, an opened sensitive file would remain open across a fork+exec to a lower-privileged SELinux domain, leaking that sensitive data. Open-like functions including open(), openat(), and open64() should include O_CLOEXEC in their flags argument.

+

Examples:

+
open("filename", O_RDWR);
+open64("filename", O_RDWR);
+openat(0, "filename", O_RDWR);
+
+// becomes
+
+open("filename", O_RDWR | O_CLOEXEC);
+open64("filename", O_RDWR | O_CLOEXEC);
+openat(0, "filename", O_RDWR | O_CLOEXEC);
+

(Clang-Tidy original name: android-cloexec-open)

+ + +#### Cloexec Pipe {#CT_AND_CP2} +

This check detects usage of pipe(). Using pipe() is not recommended, pipe2() is the suggested replacement. The check also adds the O_CLOEXEC flag that marks the file descriptor to be closed in child processes. Without this flag a sensitive file descriptor can be leaked to a child process, potentially into a lower-privileged SELinux domain.

+

Examples:

+
pipe(pipefd);
+

Suggested replacement:

+
pipe2(pipefd, O_CLOEXEC);
+

(Clang-Tidy original name: android-cloexec-pipe)

+ + +#### Cloexec Pipe2 {#CT_AND_CP} +

This checks ensures that pipe2() is called with the O_CLOEXEC flag. The check also adds the O_CLOEXEC flag that marks the file descriptor to be closed in child processes. Without this flag a sensitive file descriptor can be leaked to a child process, potentially into a lower-privileged SELinux domain.

+

Examples:

+
pipe2(pipefd, O_NONBLOCK);
+

Suggested replacement:

+
pipe2(pipefd, O_NONBLOCK | O_CLOEXEC);
+

(Clang-Tidy original name: android-cloexec-pipe2)

+ + +#### Cloexec Socket {#CT_AND_CS} +

socket() should include SOCK_CLOEXEC in its type argument to avoid the file descriptor leakage. Without this flag, an opened sensitive file would remain open across a fork+exec to a lower-privileged SELinux domain.

+

Examples:

+
socket(domain, type, SOCK_STREAM);
+
+// becomes
+
+socket(domain, type, SOCK_STREAM | SOCK_CLOEXEC);
+

(Clang-Tidy original name: android-cloexec-socket)

+ + +#### Comparison In Temp Failure Retry {#CT_AND_CITFR} +

Diagnoses comparisons that appear to be incorrectly placed in the argument to the TEMP_FAILURE_RETRY macro. Having such a use is incorrect in the vast majority of cases, and will often silently defeat the purpose of the TEMP_FAILURE_RETRY macro.

+

For context, TEMP_FAILURE_RETRY is a convenience macro provided by both glibc and Bionic. Its purpose is to repeatedly run a syscall until it either succeeds, or fails for reasons other than being interrupted.

+

Example buggy usage looks like:

+
char cs[1];
+while (TEMP_FAILURE_RETRY(read(STDIN_FILENO, cs, sizeof(cs)) != 0)) {
+  // Do something with cs.
+}
+

Because TEMP_FAILURE_RETRY will check for whether the result of the comparison is -1, and retry if so.

+

If you encounter this, the fix is simple: lift the comparison out of the TEMP_FAILURE_RETRY argument, like so:

+
char cs[1];
+while (TEMP_FAILURE_RETRY(read(STDIN_FILENO, cs, sizeof(cs))) != 0) {
+  // Do something with cs.
+}
+
Options
+

RetryMacros

+

A comma-separated list of the names of retry macros to be checked.

+

(Clang-Tidy original name: android-comparison-in-temp-failure-retry)

+ + +### Boost + +#### Use To String {#CT_BST_UTS} +

This check finds conversion from integer type like int to std::string or std::wstring using boost::lexical_cast, and replace it with calls to std::to_string and std::to_wstring.

+

It doesn’t replace conversion from floating points despite the to_string overloads, because it would change the behaviour.

+
auto str = boost::lexical_cast<std::string>(42);
+auto wstr = boost::lexical_cast<std::wstring>(2137LL);
+
+// Will be changed to
+auto str = std::to_string(42);
+auto wstr = std::to_wstring(2137LL);
+

(Clang-Tidy original name: boost-use-to-string)

+ + +### Bugprone + +#### Argument Comment {#CT_BUG_AC} +

Checks that argument comments match parameter names.

+

The check understands argument comments in the form /parameter_name=/ that are placed right before the argument.

+
void f(bool foo);
+
+...
+
+f(/*bar=*/true);
+// warning: argument name 'bar' in comment does not match parameter name 'foo'
+

The check tries to detect typos and suggest automated fixes for them.

+
Options
+

StrictMode

+

When false (default value), the check will ignore leading and trailing underscores and case when comparing names – otherwise they are taken into account.

+

IgnoreSingleArgument

+

When true, the check will ignore the single argument.

+

CommentBoolLiterals

+

When true, the check will add argument comments in the format /ParameterName=/ right before the boolean literal argument.

+

Before:

+
void foo(bool TurnKey, bool PressButton);
+
+foo(true, false);
+

After:

+
void foo(bool TurnKey, bool PressButton);
+
+foo(/*TurnKey=*/true, /*PressButton=*/false);
+

CommentIntegerLiterals

+

When true, the check will add argument comments in the format /ParameterName=/ right before the integer literal argument.

+

Before:

+
void foo(int MeaningOfLife);
+
+foo(42);
+

After:

+
void foo(int MeaningOfLife);
+
+foo(/*MeaningOfLife=*/42);
+

CommentFloatLiterals

+

When true, the check will add argument comments in the format /ParameterName=/ right before the float/double literal argument.

+

Before:

+
void foo(float Pi);
+
+foo(3.14159);
+

After:

+
void foo(float Pi);
+
+foo(/*Pi=*/3.14159);
+

CommentStringLiterals

+

When true, the check will add argument comments in the format /ParameterName=/ right before the string literal argument.

+

Before:

+
void foo(const char *String);
+void foo(const wchar_t *WideString);
+
+foo("Hello World");
+foo(L"Hello World");
+

After:

+
void foo(const char *String);
+void foo(const wchar_t *WideString);
+
+foo(/*String=*/"Hello World");
+foo(/*WideString=*/L"Hello World");
+

CommentCharacterLiterals

+

When true, the check will add argument comments in the format /ParameterName=/ right before the character literal argument.

+

Before:

+
void foo(char *Character);
+
+foo('A');
+

After:

+
void foo(char *Character);
+
+foo(/*Character=*/'A');
+

CommentUserDefinedLiterals

+

When true, the check will add argument comments in the format /ParameterName=/ right before the user defined literal argument.

+

Before:

+
void foo(double Distance);
+
+double operator"" _km(long double);
+
+foo(402.0_km);
+

After:

+
void foo(double Distance);
+
+double operator"" _km(long double);
+
+foo(/*Distance=*/402.0_km);
+

CommentNullPtrs

+

When true, the check will add argument comments in the format /ParameterName=/ right before the nullptr literal argument.

+

Before:

+
void foo(A* Value);
+
+foo(nullptr);
+

After:

+
void foo(A* Value);
+
+foo(/*Value=*/nullptr);
+

(Clang-Tidy original name: bugprone-argument-comment)

+ + +#### Assert Side Effect {#CT_BUG_ASE} +

Finds assert() with side effect.

+

The condition of assert() is evaluated only in debug builds so a condition with side effect can cause different behavior in debug / release builds.

+
Options
+

AssertMacros

+

A comma-separated list of the names of assert macros to be checked.

+

CheckFunctionCalls

+

Whether to treat non-const member and non-member functions as they produce side effects. Disabled by default because it can increase the number of false positive warnings.

+

(Clang-Tidy original name: bugprone-assert-side-effect)

+ + +#### Bad Signal To Kill Thread {#CT_BUG_BSTKT} +

Finds pthread_kill function calls when a thread is terminated by raising SIGTERM signal and the signal kills the entire process, not just the individual thread. Use any signal except SIGTERM.

+

This check corresponds to the CERT C Coding Standard rule POS44-C. Do not use signals to terminate threads.

+

(Clang-Tidy original name: bugprone-bad-signal-to-kill-thread)

+ + +#### Bool Pointer Implicit Conversion {#CT_BUG_BPIC} +

Checks for conditions based on implicit conversion from a bool pointer to bool.

+

Example:

+
bool *p;
+if (p) {
+  // Never used in a pointer-specific way.
+}
+

(Clang-Tidy original name: bugprone-bool-pointer-implicit-conversion)

+ + +#### Branch Clone {#CT_BUG_BC} +

Checks for repeated branches in if/else if/else chains, consecutive repeated branches in switch statements and identical true and false branches in conditional operators.

+
if (test_value(x)) {
+  y++;
+  do_something(x, y);
+} else {
+  y++;
+  do_something(x, y);
+}
+

In this simple example (which could arise e.g. as a copy-paste error) the then and else branches are identical and the code is equivalent the following shorter and cleaner code:

+
test_value(x); // can be omitted unless it has side effects
+y++;
+do_something(x, y);
+

If this is the intended behavior, then there is no reason to use a conditional statement; otherwise the issue can be solved by fixing the branch that is handled incorrectly.

+

The check also detects repeated branches in longer if/else if/else chains where it would be even harder to notice the problem.

+

In switch statements the check only reports repeated branches when they are consecutive, because it is relatively common that the case: labels have some natural ordering and rearranging them would decrease the readability of the code. For example:

+
switch (ch) {
+case 'a':
+  return 10;
+case 'A':
+  return 10;
+case 'b':
+  return 11;
+case 'B':
+  return 11;
+default:
+  return 10;
+}
+

Here the check reports that the 'a' and 'A' branches are identical (and that the 'b' and 'B' branches are also identical), but does not report that the default: branch is also identical to the first two branches. If this is indeed the correct behavior, then it could be implemented as:

+
switch (ch) {
+case 'a':
+case 'A':
+  return 10;
+case 'b':
+case 'B':
+  return 11;
+default:
+  return 10;
+}
+

Here the check does not warn for the repeated return 10;, which is good if we want to preserve that 'a' is before 'b' and default: is the last branch.

+

Finally, the check also examines conditional operators and reports code like:

+
return test_value(x) ? x : x;
+

Unlike if statements, the check does not detect chains of conditional operators.

+

Note: This check also reports situations where branches become identical only after preprocession.

+

(Clang-Tidy original name: bugprone-branch-clone)

+ + +#### Copy Constructor Init {#CT_BUG_CCI} +

Finds copy constructors where the constructor doesn’t call the copy constructor of the base class.

+
class Copyable {
+public:
+  Copyable() = default;
+  Copyable(const Copyable &) = default;
+};
+class X2 : public Copyable {
+  X2(const X2 &other) {} // Copyable(other) is missing
+};
+

Also finds copy constructors where the constructor of the base class don’t have parameter.

+
class X4 : public Copyable {
+  X4(const X4 &other) : Copyable() {} // other is missing
+};
+

The check also suggests a fix-its in some cases.

+

(Clang-Tidy original name: bugprone-copy-constructor-init)

+ + +#### Dangling Handle {#CT_BUG_DH} +

Detect dangling references in value handles like std::experimental::string_view. These dangling references can be a result of constructing handles from temporary values, where the temporary is destroyed soon after the handle is created.

+

Examples:

+
string_view View = string();  // View will dangle.
+string A;
+View = A + "A";  // still dangle.
+
+vector<string_view> V;
+V.push_back(string());  // V[0] is dangling.
+V.resize(3, string());  // V[1] and V[2] will also dangle.
+
+string_view f() {
+  // All these return values will dangle.
+  return string();
+  string S;
+  return S;
+  char Array[10]{};
+  return Array;
+}
+
Options
+

HandleClasses

+

A semicolon-separated list of class names that should be treated as handles. By default only std::experimental::basic_string_view is considered.

+

(Clang-Tidy original name: bugprone-dangling-handle)

+ + +#### Dynamic Static Initializers {#CT_BUG_DSI} +

Finds instances of static variables that are dynamically initialized in header files.

+

This can pose problems in certain multithreaded contexts. For example, when disabling compiler generated synchronization instructions for static variables initialized at runtime (e.g. by -fno-threadsafe-statics), even if a particular project takes the necessary precautions to prevent race conditions during initialization by providing their own synchronization, header files included from other projects may not. Therefore, such a check is helpful for ensuring that disabling compiler generated synchronization for static variable initialization will not cause problems.

+

Consider the following code:

+
int foo() {
+  static int k = bar();
+  return k;
+}
+

When synchronization of static initialization is disabled, if two threads both call foo for the first time, there is the possibility that k will be double initialized, creating a race condition.

+

(Clang-Tidy original name: bugprone-dynamic-static-initializers)

+ + +#### Exception Escape {#CT_BUG_EE} +

Finds functions which may throw an exception directly or indirectly, but they should not. The functions which should not throw exceptions are the following:

+
    +
  • Destructors
  • +
  • Move constructors
  • +
  • Move assignment operators
  • +
  • The main() functions
  • +
  • swap() functions
  • +
  • Functions marked with throw() or noexcept
  • +
  • Other functions given as option
  • +
+

A destructor throwing an exception may result in undefined behavior, resource leaks or unexpected termination of the program. Throwing move constructor or move assignment also may result in undefined behavior or resource leak. The swap() operations expected to be non throwing most of the cases and they are always possible to implement in a non throwing way. Non throwing swap() operations are also used to create move operations. A throwing main() function also results in unexpected termination.

+

WARNING! This check may be expensive on large source files.

+
Options
+

FunctionsThatShouldNotThrow

+

Comma separated list containing function names which should not throw. An example value for this parameter can be WinMain which adds function WinMain() in the Windows API to the list of the functions which should not throw. Default value is an empty string.

+

IgnoredExceptions

+

Comma separated list containing type names which are not counted as thrown exceptions in the check. Default value is an empty string.

+

(Clang-Tidy original name: bugprone-exception-escape)

+ + +#### Fold Init Type {#CT_BUG_FIT} +

The check flags type mismatches in folds like std::accumulate that might result in loss of precision. std::accumulate folds an input range into an initial value using the type of the latter, with operator+ by default. This can cause loss of precision through:

+
    +
  • Truncation: The following code uses a floating point range and an int initial value, so trucation will happen at every application of operator+ and the result will be 0, which might not be what the user expected.
  • +
+
auto a = {0.5f, 0.5f, 0.5f, 0.5f};
+return std::accumulate(std::begin(a), std::end(a), 0);
+
    +
  • Overflow: The following code also returns 0.
  • +
+
auto a = {65536LL * 65536 * 65536};
+return std::accumulate(std::begin(a), std::end(a), 0);
+

(Clang-Tidy original name: bugprone-fold-init-type)

+ + +#### Forward Declaration Namespace {#CT_BUG_FDN} +

Checks if an unused forward declaration is in a wrong namespace.

+

The check inspects all unused forward declarations and checks if there is any declaration/definition with the same name existing, which could indicate that the forward declaration is in a potentially wrong namespace.

+
namespace na { struct A; }
+namespace nb { struct A {}; }
+nb::A a;
+// warning : no definition found for 'A', but a definition with the same name
+// 'A' found in another namespace 'nb::'
+

This check can only generate warnings, but it can’t suggest a fix at this point.

+

(Clang-Tidy original name: bugprone-forward-declaration-namespace)

+ + +#### Forwarding Reference Overload {#CT_BUG_FRO} +

The check looks for perfect forwarding constructors that can hide copy or move constructors. If a non const lvalue reference is passed to the constructor, the forwarding reference parameter will be a better match than the const reference parameter of the copy constructor, so the perfect forwarding constructor will be called, which can be confusing. For detailed description of this issue see: Scott Meyers, Effective Modern C++, Item 26.

+

Consider the following example:

+
class Person {
+public:
+  // C1: perfect forwarding ctor
+  template<typename T>
+  explicit Person(T&& n) {}
+
+  // C2: perfect forwarding ctor with parameter default value
+  template<typename T>
+  explicit Person(T&& n, int x = 1) {}
+
+  // C3: perfect forwarding ctor guarded with enable_if
+  template<typename T, typename X = enable_if_t<is_special<T>,void>>
+  explicit Person(T&& n) {}
+
+  // (possibly compiler generated) copy ctor
+  Person(const Person& rhs);
+};
+

The check warns for constructors C1 and C2, because those can hide copy and move constructors. We suppress warnings if the copy and the move constructors are both disabled (deleted or private), because there is nothing the perfect forwarding constructor could hide in this case. We also suppress warnings for constructors like C3 that are guarded with an enable_if, assuming the programmer was aware of the possible hiding.

+
Background
+

For deciding whether a constructor is guarded with enable_if, we consider the default values of the type parameters and the types of the constructor parameters. If any part of these types is std::enable_if or std::enable_if_t, we assume the constructor is guarded.

+

(Clang-Tidy original name: bugprone-forwarding-reference-overload)

+ + +#### Inaccurate Erase {#CT_BUG_IE} +

Checks for inaccurate use of the erase() method.

+

Algorithms like remove() do not actually remove any element from the container but return an iterator to the first redundant element at the end of the container. These redundant elements must be removed using the erase() method. This check warns when not all of the elements will be removed due to using an inappropriate overload.

+

For example, the following code erases only one element:

+
std::vector<int> xs;
+...
+xs.erase(std::remove(xs.begin(), xs.end(), 10));
+

Call the two-argument overload of erase() to remove the subrange:

+
std::vector<int> xs;
+...
+xs.erase(std::remove(xs.begin(), xs.end(), 10), xs.end());
+

(Clang-Tidy original name: bugprone-inaccurate-erase)

+ + +#### Incorrect Roundings {#CT_BUG_IR} +

Checks the usage of patterns known to produce incorrect rounding. Programmers often use:

+
(int)(double_expression + 0.5)
+

to round the double expression to an integer. The problem with this:

+
    +
  1. It is unnecessarily slow.
  2. +
  3. It is incorrect. The number 0.499999975 (smallest representable float number below 0.5) rounds to 1.0. Even worse behavior for negative numbers where both -0.5f and -1.4f both round to 0.0.
  4. +
+

(Clang-Tidy original name: bugprone-incorrect-roundings)

+ + +#### Infinite Loop {#CT_BUG_IL} +

Finds obvious infinite loops (loops where the condition variable is not changed at all).

+

Finding infinite loops is well-known to be impossible (halting problem). However, it is possible to detect some obvious infinite loops, for example, if the loop condition is not changed. This check detects such loops. A loop is considered infinite if it does not have any loop exit statement (break, continue, goto, return, throw or a call to a function called as [[noreturn]]) and all of the following conditions hold for every variable in the condition:

+
    +
  • It is a local variable.
  • +
  • It has no reference or pointer aliases.
  • +
  • It is not a structure or class member.
  • +
+

Furthermore, the condition must not contain a function call to consider the loop infinite since functions may return different values for different calls.

+

For example, the following loop is considered infinite i is not changed in the body:

+
int i = 0, j = 0;
+while (i < 10) {
+  ++j;
+}
+

(Clang-Tidy original name: bugprone-infinite-loop)

+ + +#### Integer Division {#CT_BUG_ID} +

Finds cases where integer division in a floating point context is likely to cause unintended loss of precision.

+

No reports are made if divisions are part of the following expressions:

+
    +
  • operands of operators expecting integral or bool types,
  • +
  • call expressions of integral or bool types, and
  • +
  • explicit cast expressions to integral or bool types,
  • +
+

as these are interpreted as signs of deliberateness from the programmer.

+

Examples:

+
float floatFunc(float);
+int intFunc(int);
+double d;
+int i = 42;
+
+// Warn, floating-point values expected.
+d = 32 * 8 / (2 + i);
+d = 8 * floatFunc(1 + 7 / 2);
+d = i / (1 << 4);
+
+// OK, no integer division.
+d = 32 * 8.0 / (2 + i);
+d = 8 * floatFunc(1 + 7.0 / 2);
+d = (double)i / (1 << 4);
+
+// OK, there are signs of deliberateness.
+d = 1 << (i / 2);
+d = 9 + intFunc(6 * i / 32);
+d = (int)(i / 32) - 8;
+

(Clang-Tidy original name: bugprone-integer-division)

+ + +#### Lambda Function Name {#CT_BUG_LFN} +

Checks for attempts to get the name of a function from within a lambda expression. The name of a lambda is always something like operator(), which is almost never what was intended.

+

Example:

+
void FancyFunction() {
+  [] { printf("Called from %s\n", __func__); }();
+  [] { printf("Now called from %s\n", __FUNCTION__); }();
+}
+

Output:

+
Called from operator()
+Now called from operator()
+

Likely intended output:

+
Called from FancyFunction
+Now called from FancyFunction
+

(Clang-Tidy original name: bugprone-lambda-function-name)

+ + +#### Macro Parentheses {#CT_BUG_MP} +

Finds macros that can have unexpected behaviour due to missing parentheses.

+

Macros are expanded by the preprocessor as-is. As a result, there can be unexpected behaviour; operators may be evaluated in unexpected order and unary operators may become binary operators, etc.

+

When the replacement list has an expression, it is recommended to surround it with parentheses. This ensures that the macro result is evaluated completely before it is used.

+

It is also recommended to surround macro arguments in the replacement list with parentheses. This ensures that the argument value is calculated properly.

+

(Clang-Tidy original name: bugprone-macro-parentheses)

+

subl.. title:: clang-tidy - abseil-no-internal-dependencies

+ + +#### Macro Repeated Side Effects {#CT_BUG_MRSE} +

Checks for repeated argument with side effects in macros.

+

(Clang-Tidy original name: bugprone-macro-repeated-side-effects)

+ + +#### Misplaced Operator In Strlen In Alloc {#CT_BUG_MOISIA} +

Finds cases where 1 is added to the string in the argument to strlen(), strnlen(), strnlen_s(), wcslen(), wcsnlen(), and wcsnlen_s() instead of the result and the value is used as an argument to a memory allocation function (malloc(), calloc(), realloc(), alloca()) or the new[] operator in C++. The check detects error cases even if one of these functions (except the new[] operator) is called by a constant function pointer. Cases where 1 is added both to the parameter and the result of the strlen()-like function are ignored, as are cases where the whole addition is surrounded by extra parentheses.

+

C example code:

+
void bad_malloc(char *str) {
+  char *c = (char*) malloc(strlen(str + 1));
+}
+

The suggested fix is to add 1 to the return value of strlen() and not to its argument. In the example above the fix would be

+
char *c = (char*) malloc(strlen(str) + 1);
+

C++ example code:

+
void bad_new(char *str) {
+  char *c = new char[strlen(str + 1)];
+}
+

As in the C code with the malloc() function, the suggested fix is to add 1 to the return value of strlen() and not to its argument. In the example above the fix would be

+
char *c = new char[strlen(str) + 1];
+

Example for silencing the diagnostic:

+
void bad_malloc(char *str) {
+  char *c = (char*) malloc(strlen((str + 1)));
+}
+

(Clang-Tidy original name: bugprone-misplaced-operator-in-strlen-in-alloc)

+ + +#### Misplaced Pointer Arithmetic In Alloc {#CT_BUG_MPAIA} +

Finds cases where an integer expression is added to or subtracted from the result of a memory allocation function (malloc(), calloc(), realloc(), alloca()) instead of its argument. The check detects error cases even if one of these functions is called by a constant function pointer.

+

Example code:

+
void bad_malloc(int n) {
+  char *p = (char*) malloc(n) + 10;
+}
+

The suggested fix is to add the integer expression to the argument of malloc and not to its result. In the example above the fix would be

+
char *p = (char*) malloc(n + 10);
+

(Clang-Tidy original name: bugprone-misplaced-pointer-arithmetic-in-alloc)

+ + +#### Misplaced Widening Cast {#CT_BUG_MWC} +

This check will warn when there is a cast of a calculation result to a bigger type. If the intention of the cast is to avoid loss of precision then the cast is misplaced, and there can be loss of precision. Otherwise the cast is ineffective.

+

Example code:

+
long f(int x) {
+    return (long)(x * 1000);
+}
+

The result x * 1000 is first calculated using int precision. If the result exceeds int precision there is loss of precision. Then the result is casted to long.

+

If there is no loss of precision then the cast can be removed or you can explicitly cast to int instead.

+

If you want to avoid loss of precision then put the cast in a proper location, for instance:

+
long f(int x) {
+    return (long)x * 1000;
+}
+
Implicit casts
+

Forgetting to place the cast at all is at least as dangerous and at least as common as misplacing it. If CheckImplicitCasts is enabled the check also detects these cases, for instance:

+
long f(int x) {
+    return x * 1000;
+}
+
Floating point
+

Currently warnings are only written for integer conversion. No warning is written for this code:

+
double f(float x) {
+    return (double)(x * 10.0f);
+}
+
Options
+

CheckImplicitCasts

+

If true, enables detection of implicit casts. Default is true.

+

(Clang-Tidy original name: bugprone-misplaced-widening-cast)

+ + +#### Move Forwarding Reference {#CT_BUG_MFR} +

Warns if std::move is called on a forwarding reference, for example:

+
template <typename T>
+void foo(T&& t) {
+  bar(std::move(t));
+}
+

Forwarding references should typically be passed to std::forward instead of std::move, and this is the fix that will be suggested.

+

(A forwarding reference is an rvalue reference of a type that is a deduced function template argument.)

+

In this example, the suggested fix would be

+
bar(std::forward<T>(t));
+
Background
+

Code like the example above is sometimes written with the expectation that T&& will always end up being an rvalue reference, no matter what type is deduced for T, and that it is therefore not possible to pass an lvalue to foo(). However, this is not true. Consider this example:

+
std::string s = "Hello, world";
+foo(s);
+

This code compiles and, after the call to foo(), s is left in an indeterminate state because it has been moved from. This may be surprising to the caller of foo() because no std::move was used when calling foo().

+

The reason for this behavior lies in the special rule for template argument deduction on function templates like foo() – i.e. on function templates that take an rvalue reference argument of a type that is a deduced function template argument. (See section [temp.deduct.call]/3 in the C++11 standard.)

+

If foo() is called on an lvalue (as in the example above), then T is deduced to be an lvalue reference. In the example, T is deduced to be std::string &. The type of the argument t therefore becomes std::string& &&; by the reference collapsing rules, this collapses to std::string&.

+

This means that the foo(s) call passes s as an lvalue reference, and foo() ends up moving s and thereby placing it into an indeterminate state.

+

(Clang-Tidy original name: bugprone-move-forwarding-reference)

+ + +#### Multiple Statement Macro {#CT_BUG_MSM} +

Detect multiple statement macros that are used in unbraced conditionals. Only the first statement of the macro will be inside the conditional and the other ones will be executed unconditionally.

+

Example:

+
#define INCREMENT_TWO(x, y) (x)++; (y)++
+if (do_increment)
+  INCREMENT_TWO(a, b);  // (b)++ will be executed unconditionally.
+

(Clang-Tidy original name: bugprone-multiple-statement-macro)

+ + +#### Narrowing Conversions {#CT_BUG_NC} +No documentation is available. + +#### No Escape {#CT_BUG_NE} +

Finds pointers with the noescape attribute that are captured by an asynchronously-executed block. The block arguments in dispatch_async() and dispatch_after() are guaranteed to escape, so it is an error if a pointer with the noescape attribute is captured by one of these blocks.

+

The following is an example of an invalid use of the noescape attribute.

+
void foo(__attribute__((noescape)) int *p) {
+  dispatch_async(queue, ^{
+    *p = 123;
+  });
+});
+

(Clang-Tidy original name: bugprone-no-escape)

+ + +#### Not Null Terminated Result {#CT_BUG_NNTR} +

Finds function calls where it is possible to cause a not null-terminated result. Usually the proper length of a string is strlen(src) + 1 or equal length of this expression, because the null terminator needs an extra space. Without the null terminator it can result in undefined behaviour when the string is read.

+

The following and their respective wchar_t based functions are checked:

+

memcpy, memcpy_s, memchr, memmove, memmove_s, strerror_s, strncmp, strxfrm

+

The following is a real-world example where the programmer forgot to increase the passed third argument, which is size_t length. That is why the length of the allocated memory is not enough to hold the null terminator.

+
static char *stringCpy(const std::string &str) {
+  char *result = reinterpret_cast<char *>(malloc(str.size()));
+  memcpy(result, str.data(), str.size());
+  return result;
+}
+

In addition to issuing warnings, fix-it rewrites all the necessary code. It also tries to adjust the capacity of the destination array:

+
static char *stringCpy(const std::string &str) {
+  char *result = reinterpret_cast<char *>(malloc(str.size() + 1));
+  strcpy(result, str.data());
+  return result;
+}
+

Note: It cannot guarantee to rewrite every of the path-sensitive memory allocations.

+
Transformation rules of ‘memcpy()’
+

It is possible to rewrite the memcpy() and memcpy_s() calls as the following four functions: strcpy(), strncpy(), strcpy_s(), strncpy_s(), where the latter two are the safer versions of the former two. It rewrites the wchar_t based memory handler functions respectively.

+
Rewrite based on the destination array
+
    +
  • If copy to the destination array cannot overflow [1] the new function should be the older copy function (ending with cpy), because it is more efficient than the safe version.
  • +
  • If copy to the destination array can overflow [1] and WantToUseSafeFunctions is set to true and it is possible to obtain the capacity of the destination array then the new function could be the safe version (ending with cpy_s).
  • +
  • If the new function is could be safe version and C++ files are analysed and the destination array is plain char/wchar_t without un/signed then the length of the destination array can be omitted.
  • +
  • If the new function is could be safe version and the destination array is un/signed it needs to be casted to plain char /wchar_t .
  • +
+

[1] It is possible to overflow:

+
    +
  • If the capacity of the destination array is unknown.
  • +
  • If the given length is equal to the destination array’s capacity.
  • +
+
Rewrite based on the length of the source string
+
    +
  • If the given length is strlen(source) or equal length of this expression then the new function should be the older copy function (ending with cpy), as it is more efficient than the safe version (ending with cpy_s).
  • +
  • Otherwise we assume that the programmer wanted to copy ‘N’ characters, so the new function is ncpy-like which copies ‘N’ characters.
  • +
+
Transformations with ‘strlen()’ or equal length of this expression
+

It transforms the wchar_t based memory and string handler functions respectively (where only strerror_s does not have wchar_t based alias).

+
Memory handler functions
+

memcpy Please visit the Transformation rules of ‘memcpy()’ section.

+

memchr Usually there is a C-style cast and it is needed to be removed, because the new function strchr’s return type is correct. The given length is going to be removed.

+

memmove If safe functions are available the new function is memmove_s, which has a new second argument which is the length of the destination array, it is adjusted, and the length of the source string is incremented by one. If safe functions are not available the given length is incremented by one.

+

memmove_s The given length is incremented by one.

+
String handler functions
+

strerror_s The given length is incremented by one.

+

strncmp If the third argument is the first or the second argument’s length + 1 it has to be truncated without the + 1 operation.

+

strxfrm The given length is incremented by one.

+
Options
+

WantToUseSafeFunctions

+

The value true specifies that the target environment is considered to implement ‘_s’ suffixed memory and string handler functions which are safer than older versions (e.g. ‘memcpy_s()’). The default value is true.

+

(Clang-Tidy original name: bugprone-not-null-terminated-result)

+ + +#### Parent Virtual Call {#CT_BUG_PVC} +

Detects and fixes calls to grand-…parent virtual methods instead of calls to overridden parent’s virtual methods.

+
struct A {
+  int virtual foo() {...}
+};
+
+struct B: public A {
+  int foo() override {...}
+};
+
+struct C: public B {
+  int foo() override { A::foo(); }
+//                     ^^^^^^^^
+// warning: qualified name A::foo refers to a member overridden in subclass; did you mean 'B'?  [bugprone-parent-virtual-call]
+};
+

(Clang-Tidy original name: bugprone-parent-virtual-call)

+ + +#### Posix Return {#CT_BUG_PR} +

Checks if any calls to pthread_* or posix_* functions (except posix_openpt) expect negative return values. These functions return either 0 on success or an errno on failure, which is positive only.

+

Example buggy usage looks like:

+
if (posix_fadvise(...) < 0) {
+

This will never happen as the return value is always non-negative. A simple fix could be:

+
if (posix_fadvise(...) > 0) {
+

(Clang-Tidy original name: bugprone-posix-return)

+ + +#### Redundant Branch Condition {#CT_BUG_RBC} +

Finds condition variables in nested if statements that were also checked in the outer if statement and were not changed.

+

Simple example:

+
bool onFire = isBurning();
+if (onFire) {
+  if (onFire)
+    scream();
+}
+

Here onFire is checked both in the outer if and the inner if statement without a possible change between the two checks. The check warns for this code and suggests removal of the second checking of variable onFire.

+

The checker also detects redundant condition checks if the condition variable is an operand of a logical “and” (&&) or a logical “or” (||) operator:

+
bool onFire = isBurning();
+if (onFire) {
+  if (onFire && peopleInTheBuilding > 0)
+    scream();
+}
+
bool onFire = isBurning();
+if (onFire) {
+  if (onFire || isCollapsing())
+    scream();
+}
+

In the first case (logical “and”) the suggested fix is to remove the redundant condition variable and keep the other side of the &&. In the second case (logical “or”) the whole if is removed similarily to the simple case on the top.

+

The condition of the outer if statement may also be a logical “and” (&&) expression:

+
bool onFire = isBurning();
+if (onFire && fireFighters < 10) {
+  if (someOtherCondition()) {
+    if (onFire)
+      scream();
+  }
+}
+

The error is also detected if both the outer statement is a logical “and” (&&) and the inner statement is a logical “and” (&&) or “or” (||). The inner if statement does not have to be a direct descendant of the outer one.

+

No error is detected if the condition variable may have been changed between the two checks:

+
bool onFire = isBurning();
+if (onFire) {
+  tryToExtinguish(onFire);
+  if (onFire && peopleInTheBuilding > 0)
+    scream();
+}
+

Every possible change is considered, thus if the condition variable is not a local variable of the function, it is a volatile or it has an alias (pointer or reference) then no warning is issued.

+
Known limitations
+

The else branch is not checked currently for negated condition variable:

+
bool onFire = isBurning();
+if (onFire) {
+  scream();
+} else {
+  if (!onFire) {
+    continueWork();
+  }
+}
+

The checker currently only detects redundant checking of single condition variables. More complex expressions are not checked:

+
if (peopleInTheBuilding == 1) {
+  if (peopleInTheBuilding == 1) {
+    doSomething();
+  }
+}
+

(Clang-Tidy original name: bugprone-redundant-branch-condition)

+ + +#### Reserved Identifier {#CT_BUG_RI} +

cert-dcl37-c and cert-dcl51-cpp redirect here as an alias for this check.

+

Checks for usages of identifiers reserved for use by the implementation.

+

The C and C++ standards both reserve the following names for such use:

+
    +
  • identifiers that begin with an underscore followed by an uppercase letter;
  • +
  • identifiers in the global namespace that begin with an underscore.
  • +
+

The C standard additionally reserves names beginning with a double underscore, while the C++ standard strengthens this to reserve names with a double underscore occurring anywhere.

+

Violating the naming rules above results in undefined behavior.

+
namespace NS {
+  void __f(); // name is not allowed in user code
+  using _Int = int; // same with this
+  #define cool__macro // also this
+}
+int _g(); // disallowed in global namespace only
+

The check can also be inverted, i.e. it can be configured to flag any identifier that is not a reserved identifier. This mode is for use by e.g. standard library implementors, to ensure they don’t infringe on the user namespace.

+

This check does not (yet) check for other reserved names, e.g. macro names identical to language keywords, and names specifically reserved by language standards, e.g. C++ ‘zombie names’ and C future library directions.

+

This check corresponds to CERT C Coding Standard rule DCL37-C. Do not declare or define a reserved identifier as well as its C++ counterpart, DCL51-CPP. Do not declare or define a reserved identifier.

+
Options
+

Invert

+

If true, inverts the check, i.e. flags names that are not reserved. Default is false.

+

AllowedIdentifiers

+

Semicolon-separated list of names that the check ignores. Default is an empty list.

+

(Clang-Tidy original name: bugprone-reserved-identifier)

+ + +#### Signal Handler {#CT_BUG_SH} +

Finds functions registered as signal handlers that call non asynchronous-safe functions. Any function that cannot be determined to be an asynchronous-safe function call is assumed to be non-asynchronous-safe by the checker, including user functions for which only the declaration is visible. User function calls with visible definition are checked recursively. The check handles only C code.

+

The minimal list of asynchronous-safe system functions is: abort(), _Exit(), quick_exit() and signal() (for signal there are additional conditions that are not checked). The check accepts only these calls as asynchronous-safe.

+

This check corresponds to the CERT C Coding Standard rule SIG30-C. Call only asynchronous-safe functions within signal handlers.

+

(Clang-Tidy original name: bugprone-signal-handler)

+ + +#### Signed Char Misuse {#CT_BUG_SCM} +

cert-str34-c redirects here as an alias for this check. For the CERT alias, the DiagnoseSignedUnsignedCharComparisons option is set to false.

+

Finds those signed char -> integer conversions which might indicate a programming error. The basic problem with the signed char, that it might store the non-ASCII characters as negative values. This behavior can cause a misunderstanding of the written code both when an explicit and when an implicit conversion happens.

+

When the code contains an explicit signed char -> integer conversion, the human programmer probably expects that the converted value matches with the character code (a value from [0..255]), however, the actual value is in [-128..127] interval. To avoid this kind of misinterpretation, the desired way of converting from a signed char to an integer value is converting to unsigned char first, which stores all the characters in the positive [0..255] interval which matches the known character codes.

+

In case of implicit conversion, the programmer might not actually be aware that a conversion happened and char value is used as an integer. There are some use cases when this unawareness might lead to a functionally imperfect code. For example, checking the equality of a signed char and an unsigned char variable is something we should avoid in C++ code. During this comparison, the two variables are converted to integers which have different value ranges. For signed char, the non-ASCII characters are stored as a value in [-128..-1] interval, while the same characters are stored in the [128..255] interval for an unsigned char.

+

It depends on the actual platform whether plain char is handled as signed char by default and so it is caught by this check or not. To change the default behavior you can use -funsigned-char and -fsigned-char compilation options.

+

Currently, this check warns in the following cases: - signed char is assigned to an integer variable - signed char and unsigned char are compared with equality/inequality operator - signed char is converted to an integer in the array subscript

+

See also: STR34-C. Cast characters to unsigned char before converting to larger integer sizes

+

A good example from the CERT description when a char variable is used to read from a file that might contain non-ASCII characters. The problem comes up when the code uses the -1 integer value as EOF, while the 255 character code is also stored as -1 in two’s complement form of char type. See a simple example of this bellow. This code stops not only when it reaches the end of the file, but also when it gets a character with the 255 code.

+
#define EOF (-1)
+
+int read(void) {
+  char CChar;
+  int IChar = EOF;
+
+  if (readChar(CChar)) {
+    IChar = CChar;
+  }
+  return IChar;
+}
+

A proper way to fix the code above is converting the char variable to an unsigned char value first.

+
#define EOF (-1)
+
+int read(void) {
+  char CChar;
+  int IChar = EOF;
+
+  if (readChar(CChar)) {
+    IChar = static_cast<unsigned char>(CChar);
+  }
+  return IChar;
+}
+

Another use case is checking the equality of two char variables with different signedness. Inside the non-ASCII value range this comparison between a signed char and an unsigned char always returns false.

+
bool compare(signed char SChar, unsigned char USChar) {
+  if (SChar == USChar)
+    return true;
+  return false;
+}
+

The easiest way to fix this kind of comparison is casting one of the arguments, so both arguments will have the same type.

+
bool compare(signed char SChar, unsigned char USChar) {
+  if (static_cast<unsigned char>(SChar) == USChar)
+    return true;
+  return false;
+}
+

CharTypdefsToIgnore

+

A semicolon-separated list of typedef names. In this list, we can list typedefs for char or signed char, which will be ignored by the check. This is useful when a typedef introduces an integer alias like sal_Int8 or int8_t. In this case, human misinterpretation is not an issue.

+

DiagnoseSignedUnsignedCharComparisons

+

When true, the check will warn on signed char/unsigned char comparisons, otherwise these comparisons are ignored. By default, this option is set to true.

+

(Clang-Tidy original name: bugprone-signed-char-misuse)

+ + +#### Sizeof Container {#CT_BUG_SC} +

The check finds usages of sizeof on expressions of STL container types. Most likely the user wanted to use .size() instead.

+

All class/struct types declared in namespace std:: having a const size() method are considered containers, with the exception of std::bitset and std::array.

+

Examples:

+
std::string s;
+int a = 47 + sizeof(s); // warning: sizeof() doesn't return the size of the container. Did you mean .size()?
+
+int b = sizeof(std::string); // no warning, probably intended.
+
+std::string array_of_strings[10];
+int c = sizeof(array_of_strings) / sizeof(array_of_strings[0]); // no warning, definitely intended.
+
+std::array<int, 3> std_array;
+int d = sizeof(std_array); // no warning, probably intended.
+

(Clang-Tidy original name: bugprone-sizeof-container)

+ + +#### Sizeof Expression {#CT_BUG_SE} +

The check finds usages of sizeof expressions which are most likely errors.

+

The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. Misuse of this operator may be leading to errors and possible software vulnerabilities.

+
Suspicious usage of ‘sizeof(K)’
+

A common mistake is to query the sizeof of an integer literal. This is equivalent to query the size of its type (probably int). The intent of the programmer was probably to simply get the integer and not its size.

+
#define BUFLEN 42
+char buf[BUFLEN];
+memset(buf, 0, sizeof(BUFLEN));  // sizeof(42) ==> sizeof(int)
+
Suspicious usage of ‘sizeof(expr)’
+

In cases, where there is an enum or integer to represent a type, a common mistake is to query the sizeof on the integer or enum that represents the type that should be used by sizeof. This results in the size of the integer and not of the type the integer represents:

+
enum data_type {
+  FLOAT_TYPE,
+  DOUBLE_TYPE
+};
+
+struct data {
+  data_type type;
+  void* buffer;
+  data_type get_type() {
+    return type;
+  }
+};
+
+void f(data d, int numElements) {
+  // should be sizeof(float) or sizeof(double), depending on d.get_type()
+  int numBytes = numElements * sizeof(d.get_type());
+  ...
+}
+
Suspicious usage of ‘sizeof(this)’
+

The this keyword is evaluated to a pointer to an object of a given type. The expression sizeof(this) is returning the size of a pointer. The programmer most likely wanted the size of the object and not the size of the pointer.

+
class Point {
+  [...]
+  size_t size() { return sizeof(this); }  // should probably be sizeof(*this)
+  [...]
+};
+
Suspicious usage of ‘sizeof(char*)’
+

There is a subtle difference between declaring a string literal with char* A = "" and char A[] = "". The first case has the type char* instead of the aggregate type char[]. Using sizeof on an object declared with char* type is returning the size of a pointer instead of the number of characters (bytes) in the string literal.

+
const char* kMessage = "Hello World!";      // const char kMessage[] = "...";
+void getMessage(char* buf) {
+  memcpy(buf, kMessage, sizeof(kMessage));  // sizeof(char*)
+}
+
Suspicious usage of ‘sizeof(A*)’
+

A common mistake is to compute the size of a pointer instead of its pointee. These cases may occur because of explicit cast or implicit conversion.

+
int A[10];
+memset(A, 0, sizeof(A + 0));
+
+struct Point point;
+memset(point, 0, sizeof(&point));
+
Suspicious usage of ‘sizeof(…)/sizeof(…)’
+

Dividing sizeof expressions is typically used to retrieve the number of elements of an aggregate. This check warns on incompatible or suspicious cases.

+

In the following example, the entity has 10-bytes and is incompatible with the type int which has 4 bytes.

+
char buf[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };  // sizeof(buf) => 10
+void getMessage(char* dst) {
+  memcpy(dst, buf, sizeof(buf) / sizeof(int));  // sizeof(int) => 4  [incompatible sizes]
+}
+

In the following example, the expression sizeof(Values) is returning the size of char. One can easily be fooled by its declaration, but in parameter declaration the size ‘10’ is ignored and the function is receiving a char.

+
char OrderedValues[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+return CompareArray(char Values[10]) {
+  return memcmp(OrderedValues, Values, sizeof(Values)) == 0;  // sizeof(Values) ==> sizeof(char*) [implicit cast to char*]
+}
+
Suspicious ‘sizeof’ by ‘sizeof’ expression
+

Multiplying sizeof expressions typically makes no sense and is probably a logic error. In the following example, the programmer used * instead of /.

+
const char kMessage[] = "Hello World!";
+void getMessage(char* buf) {
+  memcpy(buf, kMessage, sizeof(kMessage) * sizeof(char));  //  sizeof(kMessage) / sizeof(char)
+}
+

This check may trigger on code using the arraysize macro. The following code is working correctly but should be simplified by using only the sizeof operator.

+
extern Object objects[100];
+void InitializeObjects() {
+  memset(objects, 0, arraysize(objects) * sizeof(Object));  // sizeof(objects)
+}
+
Suspicious usage of ‘sizeof(sizeof(…))’
+

Getting the sizeof of a sizeof makes no sense and is typically an error hidden through macros.

+
#define INT_SZ sizeof(int)
+int buf[] = { 42 };
+void getInt(int* dst) {
+  memcpy(dst, buf, sizeof(INT_SZ));  // sizeof(sizeof(int)) is suspicious.
+}
+
Options
+

WarnOnSizeOfConstant

+

When true, the check will warn on an expression like sizeof(CONSTANT). Default is true.

+

WarnOnSizeOfIntegerExpression

+

When true, the check will warn on an expression like sizeof(expr) where the expression results in an integer. Default is false.

+

WarnOnSizeOfThis

+

When true, the check will warn on an expression like sizeof(this). Default is true.

+

WarnOnSizeOfCompareToConstant

+

When true, the check will warn on an expression like sizeof(epxr) <= k for a suspicious constant k while k is 0 or greater than 0x8000. Default is true.

+

(Clang-Tidy original name: bugprone-sizeof-expression)

+ + +#### Spuriously Wake Up Functions {#CT_BUG_SWUF} +

Finds cnd_wait, cnd_timedwait, wait, wait_for, or wait_until function calls when the function is not invoked from a loop that checks whether a condition predicate holds or the function has a condition parameter.

+

This check corresponds to the CERT C++ Coding Standard rule CON54-CPP. Wrap functions that can spuriously wake up in a loop. and CERT C Coding Standard rule CON36-C. Wrap functions that can spuriously wake up in a loop.

+

(Clang-Tidy original name: bugprone-spuriously-wake-up-functions)

+ + +#### String Constructor {#CT_BUG_SC2} +

Finds string constructors that are suspicious and probably errors.

+

A common mistake is to swap parameters to the ‘fill’ string-constructor.

+

Examples:

+
std::string str('x', 50); // should be str(50, 'x')
+

Calling the string-literal constructor with a length bigger than the literal is suspicious and adds extra random characters to the string.

+

Examples:

+
std::string("test", 200);   // Will include random characters after "test".
+std::string_view("test", 200);
+

Creating an empty string from constructors with parameters is considered suspicious. The programmer should use the empty constructor instead.

+

Examples:

+
std::string("test", 0);   // Creation of an empty string.
+std::string_view("test", 0);
+
Options
+

WarnOnLargeLength

+

When true, the check will warn on a string with a length greater than LargeLengthThreshold. Default is true.

+

LargeLengthThreshold

+

An integer specifying the large length threshold. Default is 0x800000.

+

StringNames

+

Default is ::std::basic_string;::std::basic_string_view.

+

Semicolon-delimited list of class names to apply this check to. By default ::std::basic_string applies to std::string and std::wstring. Set to e.g. ::std::basic_string;llvm::StringRef;QString to perform this check on custom classes.

+

(Clang-Tidy original name: bugprone-string-constructor)

+ + +#### String Integer Assignment {#CT_BUG_SIA} +

The check finds assignments of an integer to std::basic_string (std::string, std::wstring, etc.). The source of the problem is the following assignment operator of std::basic_string:

+
basic_string& operator=( CharT ch );
+

Numeric types can be implicitly casted to character types.

+
std::string s;
+int x = 5965;
+s = 6;
+s = x;
+

Use the appropriate conversion functions or character literals.

+
std::string s;
+int x = 5965;
+s = '6';
+s = std::to_string(x);
+

In order to suppress false positives, use an explicit cast.

+
std::string s;
+s = static_cast<char>(6);
+

(Clang-Tidy original name: bugprone-string-integer-assignment)

+ + +#### String Literal With Embedded Nul {#CT_BUG_SLWEN} +

Finds occurrences of string literal with embedded NUL character and validates their usage.

+
Invalid escaping
+

Special characters can be escaped within a string literal by using their hexadecimal encoding like 42. A common mistake is to escape them like this x42 where the stands for the NUL character.

+
const char* Example[] = "Invalid character: \0x12 should be \x12";
+const char* Bytes[] = "\x03\0x02\0x01\0x00\0xFF\0xFF\0xFF";
+
Truncated literal
+

String-like classes can manipulate strings with embedded NUL as they are keeping track of the bytes and the length. This is not the case for a char* (NUL-terminated) string.

+

A common mistake is to pass a string-literal with embedded NUL to a string constructor expecting a NUL-terminated string. The bytes after the first NUL character are truncated.

+
std::string str("abc\0def");  // "def" is truncated
+str += "\0";                  // This statement is doing nothing
+if (str == "\0abc") return;   // This expression is always true
+

(Clang-Tidy original name: bugprone-string-literal-with-embedded-nul)

+ + +#### Suspicious Enum Usage {#CT_BUG_SEU} +

The checker detects various cases when an enum is probably misused (as a bitmask ).

+
    +
  1. When “ADD” or “bitwise OR” is used between two enum which come from different types and these types value ranges are not disjoint.
  2. +
+

The following cases will be investigated only using StrictMode. We regard the enum as a (suspicious) bitmask if the three conditions below are true at the same time:

+
    +
  • at most half of the elements of the enum are non pow-of-2 numbers (because of short enumerations)
  • +
  • there is another non pow-of-2 number than the enum constant representing all choices (the result “bitwise OR” operation of all enum elements)
  • +
  • enum type variable/enumconstant is used as an argument of a + or “bitwise OR ” operator
  • +
+

So whenever the non pow-of-2 element is used as a bitmask element we diagnose a misuse and give a warning.

+
    +
  1. Investigating the right hand side of += and |= operator.
  2. +
  3. Check only the enum value side of a | and + operator if one of them is not enum val.
  4. +
  5. Check both side of | or + operator where the enum values are from the same enum type.
  6. +
+

Examples:

+
enum { A, B, C };
+enum { D, E, F = 5 };
+enum { G = 10, H = 11, I = 12 };
+
+unsigned flag;
+flag =
+    A |
+    H; // OK, disjoint value intervals in the enum types ->probably good use.
+flag = B | F; // Warning, have common values so they are probably misused.
+
+// Case 2:
+enum Bitmask {
+  A = 0,
+  B = 1,
+  C = 2,
+  D = 4,
+  E = 8,
+  F = 16,
+  G = 31 // OK, real bitmask.
+};
+
+enum Almostbitmask {
+  AA = 0,
+  BB = 1,
+  CC = 2,
+  DD = 4,
+  EE = 8,
+  FF = 16,
+  GG // Problem, forgot to initialize.
+};
+
+unsigned flag = 0;
+flag |= E; // OK.
+flag |=
+    EE; // Warning at the decl, and note that it was used here as a bitmask.
+
Options
+

StrictMode

+

Default value: 0. When non-null the suspicious bitmask usage will be investigated additionally to the different enum usage check.

+

(Clang-Tidy original name: bugprone-suspicious-enum-usage)

+ + +#### Suspicious Include {#CT_BUG_SI} +

The check detects various cases when an include refers to what appears to be an implementation file, which often leads to hard-to-track-down ODR violations.

+

Examples:

+
#include "Dinosaur.hpp"     // OK, .hpp files tend not to have definitions.
+#include "Pterodactyl.h"    // OK, .h files tend not to have definitions.
+#include "Velociraptor.cpp" // Warning, filename is suspicious.
+#include_next <stdio.c>     // Warning, filename is suspicious.
+
Options
+

HeaderFileExtensions

+

Default value: ";h;hh;hpp;hxx" A semicolon-separated list of filename extensions of header files (the filename extensions should not contain a “.” prefix). For extension-less header files, use an empty string or leave an empty string between “;” if there are other filename extensions.

+

ImplementationFileExtensions

+

Default value: "c;cc;cpp;cxx" Likewise, a semicolon-separated list of filename extensions of implementation files.

+

(Clang-Tidy original name: bugprone-suspicious-include)

+ + +#### Suspicious Memset Usage {#CT_BUG_SMU} +

This check finds memset() calls with potential mistakes in their arguments. Considering the function as void* memset(void* destination, int fill_value, size_t byte_count), the following cases are covered:

+

Case 1: Fill value is a character ’0’

+

Filling up a memory area with ASCII code 48 characters is not customary, possibly integer zeroes were intended instead. The check offers a replacement of '0' with 0. Memsetting character pointers with '0' is allowed.

+

Case 2: Fill value is truncated

+

Memset converts fill_value to unsigned char before using it. If fill_value is out of unsigned character range, it gets truncated and memory will not contain the desired pattern.

+

Case 3: Byte count is zero

+

Calling memset with a literal zero in its byte_count argument is likely to be unintended and swapped with fill_value. The check offers to swap these two arguments.

+

Corresponding cpplint.py check name: runtime/memset.

+

Examples:

+
void foo() {
+  int i[5] = {1, 2, 3, 4, 5};
+  int *ip = i;
+  char c = '1';
+  char *cp = &c;
+  int v = 0;
+
+  // Case 1
+  memset(ip, '0', 1); // suspicious
+  memset(cp, '0', 1); // OK
+
+  // Case 2
+  memset(ip, 0xabcd, 1); // fill value gets truncated
+  memset(ip, 0x00, 1);   // OK
+
+  // Case 3
+  memset(ip, sizeof(int), v); // zero length, potentially swapped
+  memset(ip, 0, 1);           // OK
+}
+

(Clang-Tidy original name: bugprone-suspicious-memset-usage)

+ + +#### Suspicious Missing Comma {#CT_BUG_SMC} +

String literals placed side-by-side are concatenated at translation phase 6 (after the preprocessor). This feature is used to represent long string literal on multiple lines.

+

For instance, the following declarations are equivalent:

+
const char* A[] = "This is a test";
+const char* B[] = "This" " is a "    "test";
+

A common mistake done by programmers is to forget a comma between two string literals in an array initializer list.

+
const char* Test[] = {
+  "line 1",
+  "line 2"     // Missing comma!
+  "line 3",
+  "line 4",
+  "line 5"
+};
+

The array contains the string “line 2line3” at offset 1 (i.e. Test[1]). Clang won’t generate warnings at compile time.

+

This check may warn incorrectly on cases like:

+
const char* SupportedFormat[] = {
+  "Error %s",
+  "Code " PRIu64,   // May warn here.
+  "Warning %s",
+};
+
Options
+

SizeThreshold

+

An unsigned integer specifying the minimum size of a string literal to be considered by the check. Default is 5U.

+

RatioThreshold

+

A string specifying the maximum threshold ratio [0, 1.0] of suspicious string literals to be considered. Default is ".2".

+

MaxConcatenatedTokens

+

An unsigned integer specifying the maximum number of concatenated tokens. Default is 5U.

+

(Clang-Tidy original name: bugprone-suspicious-missing-comma)

+ + +#### Suspicious Semicolon {#CT_BUG_SS} +

Finds most instances of stray semicolons that unexpectedly alter the meaning of the code. More specifically, it looks for if, while, for and for-range statements whose body is a single semicolon, and then analyzes the context of the code (e.g. indentation) in an attempt to determine whether that is intentional.

+
if (x < y);
+{
+  x++;
+}
+

Here the body of the if statement consists of only the semicolon at the end of the first line, and x will be incremented regardless of the condition.

+
while ((line = readLine(file)) != NULL);
+  processLine(line);
+

As a result of this code, processLine() will only be called once, when the while loop with the empty body exits with line == NULL. The indentation of the code indicates the intention of the programmer.

+
if (x >= y);
+x -= y;
+

While the indentation does not imply any nesting, there is simply no valid reason to have an if statement with an empty body (but it can make sense for a loop). So this check issues a warning for the code above.

+

To solve the issue remove the stray semicolon or in case the empty body is intentional, reflect this using code indentation or put the semicolon in a new line. For example:

+
while (readWhitespace());
+  Token t = readNextToken();
+

Here the second line is indented in a way that suggests that it is meant to be the body of the while loop - whose body is in fact empty, because of the semicolon at the end of the first line.

+

Either remove the indentation from the second line:

+
while (readWhitespace());
+Token t = readNextToken();
+

… or move the semicolon from the end of the first line to a new line:

+
while (readWhitespace())
+  ;
+
+  Token t = readNextToken();
+

In this case the check will assume that you know what you are doing, and will not raise a warning.

+

(Clang-Tidy original name: bugprone-suspicious-semicolon)

+ + +#### Suspicious String Compare {#CT_BUG_SSC} +

Find suspicious usage of runtime string comparison functions. This check is valid in C and C++.

+

Checks for calls with implicit comparator and proposed to explicitly add it.

+
if (strcmp(...))       // Implicitly compare to zero
+if (!strcmp(...))      // Won't warn
+if (strcmp(...) != 0)  // Won't warn
+

Checks that compare function results (i,e, strcmp) are compared to valid constant. The resulting value is

+
<  0    when lower than,
+>  0    when greater than,
+== 0    when equals.
+

A common mistake is to compare the result to 1 or -1.

+
if (strcmp(...) == -1)  // Incorrect usage of the returned value.
+

Additionally, the check warns if the results value is implicitly cast to a suspicious non-integer type. It’s happening when the returned value is used in a wrong context.

+
if (strcmp(...) < 0.)  // Incorrect usage of the returned value.
+
Options
+

WarnOnImplicitComparison

+

When true, the check will warn on implicit comparison. true by default.

+

WarnOnLogicalNotComparison

+

When true, the check will warn on logical not comparison. false by default.

+

StringCompareLikeFunctions

+

A string specifying the comma-separated names of the extra string comparison functions. Default is an empty string. The check will detect the following string comparison functions: __builtin_memcmp, __builtin_strcasecmp, __builtin_strcmp, __builtin_strncasecmp, __builtin_strncmp, _mbscmp, _mbscmp_l, _mbsicmp, _mbsicmp_l, _mbsnbcmp, _mbsnbcmp_l, _mbsnbicmp, _mbsnbicmp_l, _mbsncmp, _mbsncmp_l, _mbsnicmp, _mbsnicmp_l, _memicmp, _memicmp_l, _stricmp, _stricmp_l, _strnicmp, _strnicmp_l, _wcsicmp, _wcsicmp_l, _wcsnicmp, _wcsnicmp_l, lstrcmp, lstrcmpi, memcmp, memicmp, strcasecmp, strcmp, strcmpi, stricmp, strncasecmp, strncmp, strnicmp, wcscasecmp, wcscmp, wcsicmp, wcsncmp, wcsnicmp, wmemcmp.

+

(Clang-Tidy original name: bugprone-suspicious-string-compare)

+ + +#### Swapped Arguments {#CT_BUG_SA} +

Finds potentially swapped arguments by looking at implicit conversions.

+

(Clang-Tidy original name: bugprone-swapped-arguments)

+ + +#### Terminating Continue {#CT_BUG_TC} +

Detects do while loops with a condition always evaluating to false that have a continue statement, as this continue terminates the loop effectively.

+
void f() {
+do {
+  // some code
+  continue; // terminating continue
+  // some other code
+} while(false);
+

(Clang-Tidy original name: bugprone-terminating-continue)

+ + +#### Throw Keyword Missing {#CT_BUG_TKM} +

Warns about a potentially missing throw keyword. If a temporary object is created, but the object’s type derives from (or is the same as) a class that has ‘EXCEPTION’, ‘Exception’ or ‘exception’ in its name, we can assume that the programmer’s intention was to throw that object.

+

Example:

+
void f(int i) {
+  if (i < 0) {
+    // Exception is created but is not thrown.
+    std::runtime_error("Unexpected argument");
+  }
+}
+

(Clang-Tidy original name: bugprone-throw-keyword-missing)

+ + +#### Too Small Loop Variable {#CT_BUG_TSLV} +

Detects those for loops that have a loop variable with a “too small” type which means this type can’t represent all values which are part of the iteration range.

+
int main() {
+  long size = 294967296l;
+  for (short i = 0; i < size; ++i) {}
+}
+

This for loop is an infinite loop because the short type can’t represent all values in the [0..size] interval.

+

In a real use case size means a container’s size which depends on the user input.

+
int doSomething(const std::vector& items) {
+  for (short i = 0; i < items.size(); ++i) {}
+}
+

This algorithm works for small amount of objects, but will lead to freeze for a a larger user input.

+

MagnitudeBitsUpperLimit

+

Upper limit for the magnitude bits of the loop variable. If it’s set the check filters out those catches in which the loop variable’s type has more magnitude bits as the specified upper limit. The default value is 16. For example, if the user sets this option to 31 (bits), then a 32-bit unsigend int is ignored by the check, however a 32-bit int is not (A 32-bit signed int has 31 magnitude bits).

+
int main() {
+  long size = 294967296l;
+  for (unsigned i = 0; i < size; ++i) {} // no warning with MagnitudeBitsUpperLimit = 31 on a system where unsigned is 32-bit
+  for (int i = 0; i < size; ++i) {} // warning with MagnitudeBitsUpperLimit = 31 on a system where int is 32-bit
+}
+

(Clang-Tidy original name: bugprone-too-small-loop-variable)

+ + +#### Undefined Memory Manipulation {#CT_BUG_UMM} +

Finds calls of memory manipulation functions memset(), memcpy() and memmove() on not TriviallyCopyable objects resulting in undefined behavior.

+

(Clang-Tidy original name: bugprone-undefined-memory-manipulation)

+ + +#### Undelegated Constructor {#CT_BUG_UC} +

Finds creation of temporary objects in constructors that look like a function call to another constructor of the same class.

+

The user most likely meant to use a delegating constructor or base class initializer.

+

(Clang-Tidy original name: bugprone-undelegated-constructor)

+ + +#### Unhandled Self Assignment {#CT_BUG_USA} +

cert-oop54-cpp redirects here as an alias for this check. For the CERT alias, the WarnOnlyIfThisHasSuspiciousField option is set to false.

+

Finds user-defined copy assignment operators which do not protect the code against self-assignment either by checking self-assignment explicitly or using the copy-and-swap or the copy-and-move method.

+

By default, this check searches only those classes which have any pointer or C array field to avoid false positives. In case of a pointer or a C array, it’s likely that self-copy assignment breaks the object if the copy assignment operator was not written with care.

+

See also: OOP54-CPP. Gracefully handle self-copy assignment

+

A copy assignment operator must prevent that self-copy assignment ruins the object state. A typical use case is when the class has a pointer field and the copy assignment operator first releases the pointed object and then tries to assign it:

+
class T {
+int* p;
+
+public:
+  T(const T &rhs) : p(rhs.p ? new int(*rhs.p) : nullptr) {}
+  ~T() { delete p; }
+
+  // ...
+
+  T& operator=(const T &rhs) {
+    delete p;
+    p = new int(*rhs.p);
+    return *this;
+  }
+};
+

There are two common C++ patterns to avoid this problem. The first is the self-assignment check:

+
class T {
+int* p;
+
+public:
+  T(const T &rhs) : p(rhs.p ? new int(*rhs.p) : nullptr) {}
+  ~T() { delete p; }
+
+  // ...
+
+  T& operator=(const T &rhs) {
+    if(this == &rhs)
+      return *this;
+
+    delete p;
+    p = new int(*rhs.p);
+    return *this;
+  }
+};
+

The second one is the copy-and-swap method when we create a temporary copy (using the copy constructor) and then swap this temporary object with this:

+
class T {
+int* p;
+
+public:
+  T(const T &rhs) : p(rhs.p ? new int(*rhs.p) : nullptr) {}
+  ~T() { delete p; }
+
+  // ...
+
+  void swap(T &rhs) {
+    using std::swap;
+    swap(p, rhs.p);
+  }
+
+  T& operator=(const T &rhs) {
+    T(rhs).swap(*this);
+    return *this;
+  }
+};
+

There is a third pattern which is less common. Let’s call it the copy-and-move method when we create a temporary copy (using the copy constructor) and then move this temporary object into this (needs a move assignment operator):

+
class T {
+int* p;
+
+public:
+  T(const T &rhs) : p(rhs.p ? new int(*rhs.p) : nullptr) {}
+  ~T() { delete p; }
+
+  // ...
+
+  T& operator=(const T &rhs) {
+    T t = rhs;
+    *this = std::move(t);
+    return *this;
+  }
+
+  T& operator=(T &&rhs) {
+    p = rhs.p;
+    rhs.p = nullptr;
+    return *this;
+  }
+};
+

WarnOnlyIfThisHasSuspiciousField

+

When true, the check will warn only if the container class of the copy assignment operator has any suspicious fields (pointer or C array). This option is set to true by default.

+

(Clang-Tidy original name: bugprone-unhandled-self-assignment)

+ + +#### Unused Raii {#CT_BUG_UR} +

Finds temporaries that look like RAII objects.

+

The canonical example for this is a scoped lock.

+
{
+  scoped_lock(&global_mutex);
+  critical_section();
+}
+

The destructor of the scoped_lock is called before the critical_section is entered, leaving it unprotected.

+

We apply a number of heuristics to reduce the false positive count of this check:

+
    +
  • Ignore code expanded from macros. Testing frameworks make heavy use of this.
  • +
  • Ignore types with trivial destructors. They are very unlikely to be RAII objects and there’s no difference when they are deleted.
  • +
  • Ignore objects at the end of a compound statement (doesn’t change behavior).
  • +
  • Ignore objects returned from a call.
  • +
+

(Clang-Tidy original name: bugprone-unused-raii)

+ + +#### Unused Return Value {#CT_BUG_URV} +

Warns on unused function return values. The checked functions can be configured.

+
Options
+

CheckedFunctions

+

Semicolon-separated list of functions to check. Defaults to ::std::async;::std::launder;::std::remove;::std::remove_if;::std::unique;::std::unique_ptr::release;::std::basic_string::empty;::std::vector::empty. This means that the calls to following functions are checked by default:

+
    +
  • std::async(). Not using the return value makes the call synchronous.
  • +
  • std::launder(). Not using the return value usually means that the function interface was misunderstood by the programmer. Only the returned pointer is “laundered”, not the argument.
  • +
  • std::remove(), std::remove_if() and std::unique(). The returned iterator indicates the boundary between elements to keep and elements to be removed. Not using the return value means that the information about which elements to remove is lost.
  • +
  • std::unique_ptr::release(). Not using the return value can lead to resource leaks if the same pointer isn’t stored anywhere else. Often, ignoring the release() return value indicates that the programmer confused the function with reset().
  • +
  • std::basic_string::empty() and std::vector::empty(). Not using the return value often indicates that the programmer confused the function with clear().
  • +
+

(Clang-Tidy original name: bugprone-unused-return-value)

+ + +#### Use After Move {#CT_BUG_UAM} +

Warns if an object is used after it has been moved, for example:

+
std::string str = "Hello, world!\n";
+std::vector<std::string> messages;
+messages.emplace_back(std::move(str));
+std::cout << str;
+

The last line will trigger a warning that str is used after it has been moved.

+

The check does not trigger a warning if the object is reinitialized after the move and before the use. For example, no warning will be output for this code:

+
messages.emplace_back(std::move(str));
+str = "Greetings, stranger!\n";
+std::cout << str;
+

The check takes control flow into account. A warning is only emitted if the use can be reached from the move. This means that the following code does not produce a warning:

+
if (condition) {
+  messages.emplace_back(std::move(str));
+} else {
+  std::cout << str;
+}
+

On the other hand, the following code does produce a warning:

+
for (int i = 0; i < 10; ++i) {
+  std::cout << str;
+  messages.emplace_back(std::move(str));
+}
+

(The use-after-move happens on the second iteration of the loop.)

+

In some cases, the check may not be able to detect that two branches are mutually exclusive. For example (assuming that i is an int):

+
if (i == 1) {
+  messages.emplace_back(std::move(str));
+}
+if (i == 2) {
+  std::cout << str;
+}
+

In this case, the check will erroneously produce a warning, even though it is not possible for both the move and the use to be executed.

+

An erroneous warning can be silenced by reinitializing the object after the move:

+
if (i == 1) {
+  messages.emplace_back(std::move(str));
+  str = "";
+}
+if (i == 2) {
+  std::cout << str;
+}
+

Subsections below explain more precisely what exactly the check considers to be a move, use, and reinitialization.

+
Unsequenced moves, uses, and reinitializations
+

In many cases, C++ does not make any guarantees about the order in which sub-expressions of a statement are evaluated. This means that in code like the following, it is not guaranteed whether the use will happen before or after the move:

+
void f(int i, std::vector<int> v);
+std::vector<int> v = { 1, 2, 3 };
+f(v[1], std::move(v));
+

In this kind of situation, the check will note that the use and move are unsequenced.

+

The check will also take sequencing rules into account when reinitializations occur in the same statement as moves or uses. A reinitialization is only considered to reinitialize a variable if it is guaranteed to be evaluated after the move and before the use.

+
Move
+

The check currently only considers calls of std::move on local variables or function parameters. It does not check moves of member variables or global variables.

+

Any call of std::move on a variable is considered to cause a move of that variable, even if the result of std::move is not passed to an rvalue reference parameter.

+

This means that the check will flag a use-after-move even on a type that does not define a move constructor or move assignment operator. This is intentional. Developers may use std::move on such a type in the expectation that the type will add move semantics in the future. If such a std::move has the potential to cause a use-after-move, we want to warn about it even if the type does not implement move semantics yet.

+

Furthermore, if the result of std::move is passed to an rvalue reference parameter, this will always be considered to cause a move, even if the function that consumes this parameter does not move from it, or if it does so only conditionally. For example, in the following situation, the check will assume that a move always takes place:

+
std::vector<std::string> messages;
+void f(std::string &&str) {
+  // Only remember the message if it isn't empty.
+  if (!str.empty()) {
+    messages.emplace_back(std::move(str));
+  }
+}
+std::string str = "";
+f(std::move(str));
+

The check will assume that the last line causes a move, even though, in this particular case, it does not. Again, this is intentional.

+

When analyzing the order in which moves, uses and reinitializations happen (see section Unsequenced moves, uses, and reinitializations), the move is assumed to occur in whichever function the result of the std::move is passed to.

+
Use
+

Any occurrence of the moved variable that is not a reinitialization (see below) is considered to be a use.

+

An exception to this are objects of type std::unique_ptr, std::shared_ptr and std::weak_ptr, which have defined move behavior (objects of these classes are guaranteed to be empty after they have been moved from). Therefore, an object of these classes will only be considered to be used if it is dereferenced, i.e. if operator*, operator-> or operator[] (in the case of std::unique_ptr) is called on it.

+

If multiple uses occur after a move, only the first of these is flagged.

+
Reinitialization
+

The check considers a variable to be reinitialized in the following cases:

+
    +
  • The variable occurs on the left-hand side of an assignment.
  • +
  • The variable is passed to a function as a non-const pointer or non-const lvalue reference. (It is assumed that the variable may be an out-parameter for the function.)
  • +
  • clear() or assign() is called on the variable and the variable is of one of the standard container types basic_string, vector, deque, forward_list, list, set, map, multiset, multimap, unordered_set, unordered_map, unordered_multiset, unordered_multimap.
  • +
  • reset() is called on the variable and the variable is of type std::unique_ptr, std::shared_ptr or std::weak_ptr.
  • +
  • A member function marked with the [[clang::reinitializes]] attribute is called on the variable.
  • +
+

If the variable in question is a struct and an individual member variable of that struct is written to, the check does not consider this to be a reinitialization – even if, eventually, all member variables of the struct are written to. For example:

+
struct S {
+  std::string str;
+  int i;
+};
+S s = { "Hello, world!\n", 42 };
+S s_other = std::move(s);
+s.str = "Lorem ipsum";
+s.i = 99;
+

The check will not consider s to be reinitialized after the last line; instead, the line that assigns to s.str will be flagged as a use-after-move. This is intentional as this pattern of reinitializing a struct is error-prone. For example, if an additional member variable is added to S, it is easy to forget to add the reinitialization for this additional member. Instead, it is safer to assign to the entire struct in one go, and this will also avoid the use-after-move warning.

+

(Clang-Tidy original name: bugprone-use-after-move)

+ + +#### Virtual Near Miss {#CT_BUG_VNM} +

Warn if a function is a near miss (ie. the name is very similar and the function signature is the same) to a virtual function from a base class.

+

Example:

+
struct Base {
+  virtual void func();
+};
+
+struct Derived : Base {
+  virtual funk();
+  // warning: 'Derived::funk' has a similar name and the same signature as virtual method 'Base::func'; did you mean to override it?
+};
+

(Clang-Tidy original name: bugprone-virtual-near-miss)

+ + +### C++ Core Guidelines + +#### Avoid C Arrays {#CT_CPP_ACA} +

The cppcoreguidelines-avoid-c-arrays check is an alias, please see modernize-avoid-c-arrays for more information.

+

(Clang-Tidy original name: cppcoreguidelines-avoid-c-arrays)

+ + +#### Avoid Goto {#CT_CPP_AG} +

The usage of goto for control flow is error prone and should be replaced with looping constructs. Only forward jumps in nested loops are accepted.

+

This check implements ES.76 from the CppCoreGuidelines and 6.3.1 from High Integrity C++.

+

For more information on why to avoid programming with goto you can read the famous paper A Case against the GO TO Statement..

+

The check diagnoses goto for backward jumps in every language mode. These should be replaced with C/C++ looping constructs.

+
// Bad, handwritten for loop.
+int i = 0;
+// Jump label for the loop
+loop_start:
+do_some_operation();
+
+if (i < 100) {
+  ++i;
+  goto loop_start;
+}
+
+// Better
+for(int i = 0; i < 100; ++i)
+  do_some_operation();
+

Modern C++ needs goto only to jump out of nested loops.

+
for(int i = 0; i < 100; ++i) {
+  for(int j = 0; j < 100; ++j) {
+    if (i * j > 500)
+      goto early_exit;
+  }
+}
+
+early_exit:
+some_operation();
+

All other uses of goto are diagnosed in C++.

+

(Clang-Tidy original name: cppcoreguidelines-avoid-goto)

+ + +#### Avoid Magic Numbers {#CT_CPP_AMN} +

The cppcoreguidelines-avoid-magic-numbers check is an alias, please see readability-magic-numbers for more information.

+

(Clang-Tidy original name: cppcoreguidelines-avoid-magic-numbers)

+ + +#### Avoid Non Const Global Variables {#CT_CPP_ANCGV} +

Finds non-const global variables as described in I.2 of C++ Core Guidelines . As R.6 of C++ Core Guidelines is a duplicate of rule I.2 it also covers that rule.

+
char a;  // Warns!
+const char b =  0;
+
+namespace some_namespace
+{
+    char c;  // Warns!
+    const char d = 0;
+}
+
+char * c_ptr1 = &some_namespace::c;  // Warns!
+char *const c_const_ptr = &some_namespace::c;  // Warns!
+char & c_reference = some_namespace::c;  // Warns!
+
+class Foo  // No Warnings inside Foo, only namespace scope is covered
+{
+public:
+    char e = 0;
+    const char f = 0;
+protected:
+    char g = 0;
+private:
+    char h = 0;
+};
+

Variables: a, c, c_ptr1, c_ptr2, c_const_ptr and c_reference, will all generate warnings since they are either: a globally accessible variable and non-const, a pointer or reference providing global access to non-const data or both.

+

(Clang-Tidy original name: cppcoreguidelines-avoid-non-const-global-variables)

+ + +#### C Copy Assignment Signature {#CT_CPP_CCAS} +

The cppcoreguidelines-c-copy-assignment-signature check is an alias, please see misc-unconventional-assign-operator for more information.

+

(Clang-Tidy original name: cppcoreguidelines-c-copy-assignment-signature)

+ + +#### Explicit Virtual Functions {#CT_CPP_EVF} +

The cppcoreguidelines-explicit-virtual-functions check is an alias, please see modernize-use-override for more information.

+

(Clang-Tidy original name: cppcoreguidelines-explicit-virtual-functions)

+ + +#### Init Variables {#CT_CPP_IV} +

Checks whether there are local variables that are declared without an initial value. These may lead to unexpected behaviour if there is a code path that reads the variable before assigning to it.

+

Only integers, booleans, floats, doubles and pointers are checked. The fix option initializes all detected values with the value of zero. An exception is float and double types, which are initialized to NaN.

+

As an example a function that looks like this:

+
void function() {
+  int x;
+  char *txt;
+  double d;
+
+  // Rest of the function.
+}
+

Would be rewritten to look like this:

+
#include <math.h>
+
+void function() {
+  int x = 0;
+  char *txt = nullptr;
+  double d = NAN;
+
+  // Rest of the function.
+}
+
Options
+

IncludeStyle

+

A string specifying which include-style is used, llvm or google. Default is llvm.

+

MathHeader

+

A string specifying the header to include to get the definition of NAN. Default is .

+

(Clang-Tidy original name: cppcoreguidelines-init-variables)

+ + +#### Interfaces Global Init {#CT_CPP_IGI} +

This check flags initializers of globals that access extern objects, and therefore can lead to order-of-initialization problems.

+

This rule is part of the “Interfaces” profile of the C++ Core Guidelines, see https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Ri-global-init

+

Note that currently this does not flag calls to non-constexpr functions, and therefore globals could still be accessed from functions themselves.

+

(Clang-Tidy original name: cppcoreguidelines-interfaces-global-init)

+ + +#### Macro Usage {#CT_CPP_MU} +

Finds macro usage that is considered problematic because better language constructs exist for the task.

+

The relevant sections in the C++ Core Guidelines are Enum.1, ES.30, ES.31 and ES.33.

+
Options
+

AllowedRegexp

+

A regular expression to filter allowed macros. For example DEBUG|LIBTORRENT|TORRENT|UNI could be applied to filter libtorrent. Default value is ^DEBUG_*.

+

CheckCapsOnly

+

Boolean flag to warn on all macros except those with CAPS_ONLY names. This option is intended to ease introduction of this check into older code bases. Default value is false.

+

IgnoreCommandLineMacros

+

Boolean flag to toggle ignoring command-line-defined macros. Default value is true.

+

(Clang-Tidy original name: cppcoreguidelines-macro-usage)

+ + +#### Narrowing Conversions {#CT_CPP_NC} +

Checks for silent narrowing conversions, e.g: int i = 0; i += 0.1;. While the issue is obvious in this former example, it might not be so in the following: void MyClass::f(double d) { int_member_ += d; }.

+

This rule is part of the “Expressions and statements” profile of the C++ Core Guidelines, corresponding to rule ES.46. See

+

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#es46-avoid-lossy-narrowing-truncating-arithmetic-conversions.

+

We enforce only part of the guideline, more specifically, we flag narrowing conversions from:

+
    +
  • an integer to a narrower integer (e.g. char to unsigned char),
  • +
  • an integer to a narrower floating-point (e.g. uint64_t to float),
  • +
  • a floating-point to an integer (e.g. double to int),
  • +
  • a floating-point to a narrower floating-point (e.g. double to float) if WarnOnFloatingPointNarrowingConversion Option is set.
  • +
+

This check will flag:

+
    +
  • All narrowing conversions that are not marked by an explicit cast (c-style or static_cast). For example: int i = 0; i += 0.1;, void f(int); f(0.1);,
  • +
  • All applications of binary operators with a narrowing conversions. For example: int i; i+= 0.1;.
  • +
+
Options
+

WarnOnFloatingPointNarrowingConversion

+

When true, the check will warn on narrowing floating point conversion (e.g. double to float). true by default.

+

PedanticMode

+

When true, the check will warn on assigning a floating point constant to an integer value even if the floating point value is exactly representable in the destination type (e.g. int i = 1.0;). false by default.

+
FAQ
+
    +
  • What does “narrowing conversion from ‘int’ to ‘float’” mean?
  • +
+

An IEEE754 Floating Point number can represent all integer values in the range [-2^PrecisionBits, 2^PrecisionBits] where PrecisionBits is the number of bits in the mantissa.

+

For float this would be [-2^23, 2^23], where int can represent values in the range [-2^31, 2^31-1].

+
    +
  • What does “implementation-defined” mean?
  • +
+

You may have encountered messages like “narrowing conversion from ‘unsigned int’ to signed type ‘int’ is implementation-defined”. The C/C++ standard does not mandate two’s complement for signed integers, and so the compiler is free to define what the semantics are for converting an unsigned integer to signed integer. Clang’s implementation uses the two’s complement format.

+

(Clang-Tidy original name: cppcoreguidelines-narrowing-conversions)

+ + +#### No Malloc {#CT_CPP_NM} +

This check handles C-Style memory management using malloc(), realloc(), calloc() and free(). It warns about its use and tries to suggest the use of an appropriate RAII object. Furthermore, it can be configured to check against a user-specified list of functions that are used for memory management (e.g. posix_memalign()). See C++ Core Guidelines.

+

There is no attempt made to provide fix-it hints, since manual resource management isn’t easily transformed automatically into RAII.

+
// Warns each of the following lines.
+// Containers like std::vector or std::string should be used.
+char* some_string = (char*) malloc(sizeof(char) * 20);
+char* some_string = (char*) realloc(sizeof(char) * 30);
+free(some_string);
+
+int* int_array = (int*) calloc(30, sizeof(int));
+
+// Rather use a smartpointer or stack variable.
+struct some_struct* s = (struct some_struct*) malloc(sizeof(struct some_struct));
+
Options
+

Allocations

+

Semicolon-separated list of fully qualified names of memory allocation functions. Defaults to ::malloc;::calloc.

+

Deallocations

+

Semicolon-separated list of fully qualified names of memory allocation functions. Defaults to ::free.

+

Reallocations

+

Semicolon-separated list of fully qualified names of memory allocation functions. Defaults to ::realloc.

+

(Clang-Tidy original name: cppcoreguidelines-no-malloc)

+ + +#### Non Private Member Variables In Classes {#CT_CPP_NPMVIC} +

The cppcoreguidelines-non-private-member-variables-in-classes check is an alias, please see misc-non-private-member-variables-in-classes for more information.

+

(Clang-Tidy original name: cppcoreguidelines-non-private-member-variables-in-classes)

+ + +#### Owning Memory {#CT_CPP_OM} +

This check implements the type-based semantics of gsl::owner, which allows static analysis on code, that uses raw pointers to handle resources like dynamic memory, but won’t introduce RAII concepts.

+

The relevant sections in the C++ Core Guidelines are I.11, C.33, R.3 and GSL.Views The definition of a gsl::owner is straight forward

+
namespace gsl { template <typename T> owner = T; }
+

It is therefore simple to introduce the owner even without using an implementation of the Guideline Support Library.

+

All checks are purely type based and not (yet) flow sensitive.

+

The following examples will demonstrate the correct and incorrect initializations of owners, assignment is handled the same way. Note that both new and malloc()-like resource functions are considered to produce resources.

+
// Creating an owner with factory functions is checked.
+gsl::owner<int*> function_that_returns_owner() { return gsl::owner<int*>(new int(42)); }
+
+// Dynamic memory must be assigned to an owner
+int* Something = new int(42); // BAD, will be caught
+gsl::owner<int*> Owner = new int(42); // Good
+gsl::owner<int*> Owner = new int[42]; // Good as well
+
+// Returned owner must be assigned to an owner
+int* Something = function_that_returns_owner(); // Bad, factory function
+gsl::owner<int*> Owner = function_that_returns_owner(); // Good, result lands in owner
+
+// Something not a resource or owner should not be assigned to owners
+int Stack = 42;
+gsl::owner<int*> Owned = &Stack; // Bad, not a resource assigned
+

In the case of dynamic memory as resource, only gsl::owner variables are allowed to be deleted.

+
// Example Bad, non-owner as resource handle, will be caught.
+int* NonOwner = new int(42); // First warning here, since new must land in an owner
+delete NonOwner; // Second warning here, since only owners are allowed to be deleted
+
+// Example Good, Ownership correctly stated
+gsl::owner<int*> Owner = new int(42); // Good
+delete Owner; // Good as well, statically enforced, that only owners get deleted
+

The check will furthermore ensure, that functions, that expect a gsl::owner as argument get called with either a gsl::owner or a newly created resource.

+
void expects_owner(gsl::owner<int*> o) { delete o; }
+
+// Bad Code
+int NonOwner = 42;
+expects_owner(&NonOwner); // Bad, will get caught
+
+// Good Code
+gsl::owner<int*> Owner = new int(42);
+expects_owner(Owner); // Good
+expects_owner(new int(42)); // Good as well, recognized created resource
+
+// Port legacy code for better resource-safety
+gsl::owner<FILE*> File = fopen("my_file.txt", "rw+");
+FILE* BadFile = fopen("another_file.txt", "w"); // Bad, warned
+
+// ... use the file
+
+fclose(File); // Ok, File is annotated as 'owner<>'
+fclose(BadFile); // BadFile is not an 'owner<>', will be warned
+
Options
+

LegacyResourceProducers

+

Semicolon-separated list of fully qualified names of legacy functions that create resources but cannot introduce gsl::owner<>. Defaults to ::malloc;::aligned_alloc;::realloc;::calloc;::fopen;::freopen;::tmpfile.

+

LegacyResourceConsumers

+

Semicolon-separated list of fully qualified names of legacy functions expecting resource owners as pointer arguments but cannot introduce gsl::owner<>. Defaults to ::free;::realloc;::freopen;::fclose.

+
Limitations
+

Using gsl::owner in a typedef or alias is not handled correctly.

+
using heap_int = gsl::owner<int*>;
+heap_int allocated = new int(42); // False positive!
+

The gsl::owner is declared as a templated type alias. In template functions and classes, like in the example below, the information of the type aliases gets lost. Therefore using gsl::owner in a heavy templated code base might lead to false positives.

+

Known code constructs that do not get diagnosed correctly are:

+
    +
  • std::exchange
  • +
  • std::vector>
  • +
+
// This template function works as expected. Type information doesn't get lost.
+template <typename T>
+void delete_owner(gsl::owner<T*> owned_object) {
+  delete owned_object; // Everything alright
+}
+
+gsl::owner<int*> function_that_returns_owner() { return gsl::owner<int*>(new int(42)); }
+
+// Type deduction does not work for auto variables.
+// This is caught by the check and will be noted accordingly.
+auto OwnedObject = function_that_returns_owner(); // Type of OwnedObject will be int*
+
+// Problematic function template that looses the typeinformation on owner
+template <typename T>
+void bad_template_function(T some_object) {
+  // This line will trigger the warning, that a non-owner is assigned to an owner
+  gsl::owner<T*> new_owner = some_object;
+}
+
+// Calling the function with an owner still yields a false positive.
+bad_template_function(gsl::owner<int*>(new int(42)));
+
+
+// The same issue occurs with templated classes like the following.
+template <typename T>
+class OwnedValue {
+public:
+  const T getValue() const { return _val; }
+private:
+  T _val;
+};
+
+// Code, that yields a false positive.
+OwnedValue<gsl::owner<int*>> Owner(new int(42)); // Type deduction yield T -> int *
+// False positive, getValue returns int* and not gsl::owner<int*>
+gsl::owner<int*> OwnedInt = Owner.getValue();
+

Another limitation of the current implementation is only the type based checking. Suppose you have code like the following:

+
// Two owners with assigned resources
+gsl::owner<int*> Owner1 = new int(42);
+gsl::owner<int*> Owner2 = new int(42);
+
+Owner2 = Owner1; // Conceptual Leak of initial resource of Owner2!
+Owner1 = nullptr;
+

The semantic of a gsl::owner is mostly like a std::unique_ptr, therefore assignment of two gsl::owner is considered a move, which requires that the resource Owner2 must have been released before the assignment. This kind of condition could be caught in later improvements of this check with flowsensitive analysis. Currently, the Clang Static Analyzer catches this bug for dynamic memory, but not for general types of resources.

+

(Clang-Tidy original name: cppcoreguidelines-owning-memory)

+ + +#### Prefer Member Initializer {#CT_CPP_PMI} +

Finds member initializations in the constructor body which can be converted into member initializers of the constructor instead. This not only improves the readability of the code but also positively affects its performance. Class-member assignments inside a control statement or following the first control statement are ignored.

+

This check implements C.49 from the CppCoreGuidelines.

+

If the language version is C++ 11 or above, the constructor is the default constructor of the class, the field is not a bitfield (only in case of earlier language version than C++ 20), furthermore the assigned value is a literal, negated literal or enum constant then the preferred place of the initialization is at the class member declaration.

+

This latter rule is C.48 from CppCoreGuidelines.

+

Please note, that this check does not enforce this latter rule for initializations already implemented as member initializers. For that purpose see check modernize-use-default-member-init.

+
Example 1
+
class C {
+  int n;
+  int m;
+public:
+  C() {
+    n = 1; // Literal in default constructor
+    if (dice())
+      return;
+    m = 1;
+  }
+};
+

Here n can be initialized using a default member initializer, unlike m, as m’s initialization follows a control statement (if):

+
class C {
+  int n{1};
+  int m;
+public:
+  C() {
+    if (dice())
+      return;
+    m = 1;
+  }
+
Example 2
+
class C {
+  int n;
+  int m;
+public:
+  C(int nn, int mm) {
+    n = nn; // Neither default constructor nor literal
+    if (dice())
+      return;
+    m = mm;
+  }
+};
+

Here n can be initialized in the constructor initialization list, unlike m, as m’s initialization follows a control statement (if):

+
C(int nn, int mm) : n(nn) {
+  if (dice())
+    return;
+  m = mm;
+}
+

UseAssignment

+

If this option is set to true (default is false), the check will initialize members with an assignment. In this case the fix of the first example looks like this:

+
class C {
+  int n = 1;
+  int m;
+public:
+  C() {
+    if (dice())
+      return;
+    m = 1;
+  }
+};
+

(Clang-Tidy original name: cppcoreguidelines-prefer-member-initializer)

+ + +#### Pro Bounds Array To Pointer Decay {#CT_CPP_PBATPD} +

This check flags all array to pointer decays.

+

Pointers should not be used as arrays. span is a bounds-checked, safe alternative to using pointers to access arrays.

+

This rule is part of the “Bounds safety” profile of the C++ Core Guidelines, see https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-bounds-decay.

+

(Clang-Tidy original name: cppcoreguidelines-pro-bounds-array-to-pointer-decay)

+ + +#### Pro Bounds Constant Array Index {#CT_CPP_PBCAI} +

This check flags all array subscript expressions on static arrays and std::arrays that either do not have a constant integer expression index or are out of bounds (for std::array). For out-of-bounds checking of static arrays, see the -Warray-bounds Clang diagnostic.

+

This rule is part of the “Bounds safety” profile of the C++ Core Guidelines, see https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-bounds-arrayindex.

+
Options
+

GslHeader

+

The check can generate fixes after this option has been set to the name of the include file that contains gsl::at(), e.g. “gsl/gsl.h”.

+

IncludeStyle

+

A string specifying which include-style is used, llvm or google. Default is llvm.

+

(Clang-Tidy original name: cppcoreguidelines-pro-bounds-constant-array-index)

+ + +#### Pro Bounds Pointer Arithmetic {#CT_CPP_PBPA} +

This check flags all usage of pointer arithmetic, because it could lead to an invalid pointer. Subtraction of two pointers is not flagged by this check.

+

Pointers should only refer to single objects, and pointer arithmetic is fragile and easy to get wrong. span is a bounds-checked, safe type for accessing arrays of data.

+

This rule is part of the “Bounds safety” profile of the C++ Core Guidelines, see https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-bounds-arithmetic.

+

(Clang-Tidy original name: cppcoreguidelines-pro-bounds-pointer-arithmetic)

+ + +#### Pro Type Const Cast {#CT_CPP_PTCC} +

This check flags all uses of const_cast in C++ code.

+

Modifying a variable that was declared const is undefined behavior, even with const_cast.

+

This rule is part of the “Type safety” profile of the C++ Core Guidelines, see https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-type-constcast.

+

(Clang-Tidy original name: cppcoreguidelines-pro-type-const-cast)

+ + +#### Pro Type Cstyle Cast {#CT_CPP_PTCC2} +

This check flags all use of C-style casts that perform a static_cast downcast, const_cast, or reinterpret_cast.

+

Use of these casts can violate type safety and cause the program to access a variable that is actually of type X to be accessed as if it were of an unrelated type Z. Note that a C-style (T)expression cast means to perform the first of the following that is possible: a const_cast, a static_cast, a static_cast followed by a const_cast, a reinterpret_cast, or a reinterpret_cast followed by a const_cast. This rule bans (T)expression only when used to perform an unsafe cast.

+

This rule is part of the “Type safety” profile of the C++ Core Guidelines, see https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-type-cstylecast.

+

(Clang-Tidy original name: cppcoreguidelines-pro-type-cstyle-cast)

+ + +#### Pro Type Member Init {#CT_CPP_PTMI} +

The check flags user-defined constructor definitions that do not initialize all fields that would be left in an undefined state by default construction, e.g. builtins, pointers and record types without user-provided default constructors containing at least one such type. If these fields aren’t initialized, the constructor will leave some of the memory in an undefined state.

+

For C++11 it suggests fixes to add in-class field initializers. For older versions it inserts the field initializers into the constructor initializer list. It will also initialize any direct base classes that need to be zeroed in the constructor initializer list.

+

The check takes assignment of fields in the constructor body into account but generates false positives for fields initialized in methods invoked in the constructor body.

+

The check also flags variables with automatic storage duration that have record types without a user-provided constructor and are not initialized. The suggested fix is to zero initialize the variable via {} for C++11 and beyond or = {} for older language versions.

+
Options
+

IgnoreArrays

+

If set to true, the check will not warn about array members that are not zero-initialized during construction. For performance critical code, it may be important to not initialize fixed-size array members. Default is false.

+

UseAssignment

+

If set to true, the check will provide fix-its with literal initializers ( int i = 0; ) instead of curly braces ( int i{}; ).

+

This rule is part of the “Type safety” profile of the C++ Core Guidelines, corresponding to rule Type.6. See https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-type-memberinit.

+

(Clang-Tidy original name: cppcoreguidelines-pro-type-member-init)

+ + +#### Pro Type Reinterpret Cast {#CT_CPP_PTRC} +

This check flags all uses of reinterpret_cast in C++ code.

+

Use of these casts can violate type safety and cause the program to access a variable that is actually of type X to be accessed as if it were of an unrelated type Z.

+

This rule is part of the “Type safety” profile of the C++ Core Guidelines, see https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-type-reinterpretcast.

+

(Clang-Tidy original name: cppcoreguidelines-pro-type-reinterpret-cast)

+ + +#### Pro Type Static Cast Downcast {#CT_CPP_PTSCD} +

This check flags all usages of static_cast, where a base class is casted to a derived class. In those cases, a fix-it is provided to convert the cast to a dynamic_cast.

+

Use of these casts can violate type safety and cause the program to access a variable that is actually of type X to be accessed as if it were of an unrelated type Z.

+

This rule is part of the “Type safety” profile of the C++ Core Guidelines, see https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-type-downcast.

+

(Clang-Tidy original name: cppcoreguidelines-pro-type-static-cast-downcast)

+ + +#### Pro Type Union Access {#CT_CPP_PTUA} +

This check flags all access to members of unions. Passing unions as a whole is not flagged.

+

Reading from a union member assumes that member was the last one written, and writing to a union member assumes another member with a nontrivial destructor had its destructor called. This is fragile because it cannot generally be enforced to be safe in the language and so relies on programmer discipline to get it right.

+

This rule is part of the “Type safety” profile of the C++ Core Guidelines, see https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-type-unions.

+

(Clang-Tidy original name: cppcoreguidelines-pro-type-union-access)

+ + +#### Pro Type Vararg {#CT_CPP_PTV} +

This check flags all calls to c-style vararg functions and all use of va_arg.

+

To allow for SFINAE use of vararg functions, a call is not flagged if a literal 0 is passed as the only vararg argument.

+

Passing to varargs assumes the correct type will be read. This is fragile because it cannot generally be enforced to be safe in the language and so relies on programmer discipline to get it right.

+

This rule is part of the “Type safety” profile of the C++ Core Guidelines, see https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-type-varargs.

+

(Clang-Tidy original name: cppcoreguidelines-pro-type-vararg)

+ + +#### Slicing {#CT_CPP_S} +

Flags slicing of member variables or vtable. Slicing happens when copying a derived object into a base object: the members of the derived object (both member variables and virtual member functions) will be discarded. This can be misleading especially for member function slicing, for example:

+
struct B { int a; virtual int f(); };
+struct D : B { int b; int f() override; };
+
+void use(B b) {  // Missing reference, intended?
+  b.f();  // Calls B::f.
+}
+
+D d;
+use(d);  // Slice.
+

See the relevant C++ Core Guidelines sections for details: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#es63-dont-slice https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#c145-access-polymorphic-objects-through-pointers-and-references

+

(Clang-Tidy original name: cppcoreguidelines-slicing)

+ + +#### Special Member Functions {#CT_CPP_SMF} +

The check finds classes where some but not all of the special member functions are defined.

+

By default the compiler defines a copy constructor, copy assignment operator, move constructor, move assignment operator and destructor. The default can be suppressed by explicit user-definitions. The relationship between which functions will be suppressed by definitions of other functions is complicated and it is advised that all five are defaulted or explicitly defined.

+

Note that defining a function with = delete is considered to be a definition.

+

This rule is part of the “Constructors, assignments, and destructors” profile of the C++ Core Guidelines, corresponding to rule C.21. See

+

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#c21-if-you-define-or-delete-any-default-operation-define-or-delete-them-all.

+
Options
+

AllowSoleDefaultDtor

+

When set to true (default is false), this check doesn’t flag classes with a sole, explicitly defaulted destructor. An example for such a class is:

+
struct A {
+  virtual ~A() = default;
+};
+

AllowMissingMoveFunctions

+

When set to true (default is false), this check doesn’t flag classes which define no move operations at all. It still flags classes which define only one of either move constructor or move assignment operator. With this option enabled, the following class won’t be flagged:

+
struct A {
+  A(const A&);
+  A& operator=(const A&);
+  ~A();
+};
+

AllowMissingMoveFunctionsWhenCopyIsDeleted

+

When set to true (default is false), this check doesn’t flag classes which define deleted copy operations but don’t define move operations. This flags is related to Google C++ Style Guide https://google.github.io/styleguide/cppguide.html\#Copyable_Movable_Types. With this option enabled, the following class won’t be flagged:

+
struct A {
+  A(const A&) = delete;
+  A& operator=(const A&) = delete;
+  ~A();
+};
+

(Clang-Tidy original name: cppcoreguidelines-special-member-functions)

+ + +### Cert + +#### Con36 C {#CT_CRT_CON36_C} +

The cert-con36-c check is an alias, please see bugprone-spuriously-wake-up-functions for more information.

+

(Clang-Tidy original name: cert-con36-c)

+ + +#### Con54 Cpp {#CT_CRT_CON54_CPP} +

The cert-con54-cpp check is an alias, please see bugprone-spuriously-wake-up-functions for more information.

+

(Clang-Tidy original name: cert-con54-cpp)

+ + +#### Dcl03 C {#CT_CRT_DCL03_C} +

The cert-dcl03-c check is an alias, please see misc-static-assert for more information.

+

(Clang-Tidy original name: cert-dcl03-c)

+ + +#### Dcl16 C {#CT_CRT_DCL16_C} +

The cert-dcl16-c check is an alias, please see readability-uppercase-literal-suffix for more information.

+

(Clang-Tidy original name: cert-dcl16-c)

+ + +#### Dcl21 Cpp {#CT_CRT_DCL21_CPP} +

This check flags postfix operator++ and operator-- declarations if the return type is not a const object. This also warns if the return type is a reference type.

+

The object returned by a postfix increment or decrement operator is supposed to be a snapshot of the object’s value prior to modification. With such an implementation, any modifications made to the resulting object from calling operator++(int) would be modifying a temporary object. Thus, such an implementation of a postfix increment or decrement operator should instead return a const object, prohibiting accidental mutation of a temporary object. Similarly, it is unexpected for the postfix operator to return a reference to its previous state, and any subsequent modifications would be operating on a stale object.

+

This check corresponds to the CERT C++ Coding Standard recommendation DCL21-CPP. Overloaded postfix increment and decrement operators should return a const object. However, all of the CERT recommendations have been removed from public view, and so their justification for the behavior of this check requires an account on their wiki to view.

+

(Clang-Tidy original name: cert-dcl21-cpp)

+ + +#### Dcl37 C {#CT_CRT_DCL37_C} +

The cert-dcl37-c check is an alias, please see bugprone-reserved-identifier for more information.

+

(Clang-Tidy original name: cert-dcl37-c)

+ + +#### Dcl50 Cpp {#CT_CRT_DCL50_CPP} +

This check flags all function definitions (but not declarations) of C-style variadic functions.

+

This check corresponds to the CERT C++ Coding Standard rule DCL50-CPP. Do not define a C-style variadic function.

+

(Clang-Tidy original name: cert-dcl50-cpp)

+ + +#### Dcl51 Cpp {#CT_CRT_DCL51_CPP} +

The cert-dcl51-cpp check is an alias, please see bugprone-reserved-identifier for more information.

+

(Clang-Tidy original name: cert-dcl51-cpp)

+ + +#### Dcl54 Cpp {#CT_CRT_DCL54_CPP} +

The cert-dcl54-cpp check is an alias, please see misc-new-delete-overloads for more information.

+

(Clang-Tidy original name: cert-dcl54-cpp)

+ + +#### Dcl58 Cpp {#CT_CRT_DCL58_CPP} +

Modification of the std or posix namespace can result in undefined behavior. This check warns for such modifications.

+

Examples:

+
namespace std {
+  int x; // May cause undefined behavior.
+}
+

This check corresponds to the CERT C++ Coding Standard rule DCL58-CPP. Do not modify the standard namespaces.

+

(Clang-Tidy original name: cert-dcl58-cpp)

+ + +#### Dcl59 Cpp {#CT_CRT_DCL59_CPP} +

The cert-dcl59-cpp check is an alias, please see google-build-namespaces for more information.

+

(Clang-Tidy original name: cert-dcl59-cpp)

+ + +#### Env33 C {#CT_CRT_ENV33_C} +

This check flags calls to system(), popen(), and _popen(), which execute a command processor. It does not flag calls to system() with a null pointer argument, as such a call checks for the presence of a command processor but does not actually attempt to execute a command.

+

This check corresponds to the CERT C Coding Standard rule ENV33-C. Do not call system().

+

(Clang-Tidy original name: cert-env33-c)

+ + +#### Err09 Cpp {#CT_CRT_ERR09_CPP} +

The cert-err09-cpp check is an alias, please see misc-throw-by-value-catch-by-reference for more information.

+

This check corresponds to the CERT C++ Coding Standard recommendation ERR09-CPP. Throw anonymous temporaries. However, all of the CERT recommendations have been removed from public view, and so their justification for the behavior of this check requires an account on their wiki to view.

+

(Clang-Tidy original name: cert-err09-cpp)

+ + +#### Err34 C {#CT_CRT_ERR34_C} +

This check flags calls to string-to-number conversion functions that do not verify the validity of the conversion, such as atoi() or scanf(). It does not flag calls to strtol(), or other, related conversion functions that do perform better error checking.

+
#include <stdlib.h>
+
+void func(const char *buff) {
+  int si;
+
+  if (buff) {
+    si = atoi(buff); /* 'atoi' used to convert a string to an integer, but function will
+                         not report conversion errors; consider using 'strtol' instead. */
+  } else {
+    /* Handle error */
+  }
+}
+

This check corresponds to the CERT C Coding Standard rule ERR34-C. Detect errors when converting a string to a number.

+

(Clang-Tidy original name: cert-err34-c)

+ + +#### Err52 Cpp {#CT_CRT_ERR52_CPP} +

This check flags all call expressions involving setjmp() and longjmp().

+

This check corresponds to the CERT C++ Coding Standard rule ERR52-CPP. Do not use setjmp() or longjmp().

+

(Clang-Tidy original name: cert-err52-cpp)

+ + +#### Err58 Cpp {#CT_CRT_ERR58_CPP} +

This check flags all static or thread_local variable declarations where the initializer for the object may throw an exception.

+

This check corresponds to the CERT C++ Coding Standard rule ERR58-CPP. Handle all exceptions thrown before main() begins executing.

+

(Clang-Tidy original name: cert-err58-cpp)

+ + +#### Err60 Cpp {#CT_CRT_ERR60_CPP} +

This check flags all throw expressions where the exception object is not nothrow copy constructible.

+

This check corresponds to the CERT C++ Coding Standard rule ERR60-CPP. Exception objects must be nothrow copy constructible.

+

(Clang-Tidy original name: cert-err60-cpp)

+ + +#### Err61 Cpp {#CT_CRT_ERR61_CPP} +

The cert-err61-cpp check is an alias, please see misc-throw-by-value-catch-by-reference for more information.

+

(Clang-Tidy original name: cert-err61-cpp)

+ + +#### Fio38 C {#CT_CRT_FIO38_C} +

The cert-fio38-c check is an alias, please see misc-non-copyable-objects for more information.

+

(Clang-Tidy original name: cert-fio38-c)

+ + +#### Flp30 C {#CT_CRT_FLP30_C} +

This check flags for loops where the induction expression has a floating-point type.

+

This check corresponds to the CERT C Coding Standard rule FLP30-C. Do not use floating-point variables as loop counters.

+

(Clang-Tidy original name: cert-flp30-c)

+ + +#### Mem57 Cpp {#CT_CRT_MEM57_CPP} +

This check flags uses of default operator new where the type has extended alignment (an alignment greater than the fundamental alignment). (The default operator new is guaranteed to provide the correct alignment if the requested alignment is less or equal to the fundamental alignment). Only cases are detected (by design) where the operator new is not user-defined and is not a placement new (the reason is that in these cases we assume that the user provided the correct memory allocation).

+

This check corresponds to the CERT C++ Coding Standard rule MEM57-CPP. Avoid using default operator new for over-aligned types.

+

(Clang-Tidy original name: cert-mem57-cpp)

+ + +#### Msc30 C {#CT_CRT_MSC30_C} +

The cert-msc30-c check is an alias, please see cert-msc50-cpp for more information.

+

(Clang-Tidy original name: cert-msc30-c)

+ + +#### Msc32 C {#CT_CRT_MSC32_C} +

The cert-msc32-c check is an alias, please see cert-msc51-cpp for more information.

+

(Clang-Tidy original name: cert-msc32-c)

+ + +#### Msc50 Cpp {#CT_CRT_MSC50_CPP} +

Pseudorandom number generators use mathematical algorithms to produce a sequence of numbers with good statistical properties, but the numbers produced are not genuinely random. The std::rand() function takes a seed (number), runs a mathematical operation on it and returns the result. By manipulating the seed the result can be predictable. This check warns for the usage of std::rand().

+

(Clang-Tidy original name: cert-msc50-cpp)

+ + +#### Msc51 Cpp {#CT_CRT_MSC51_CPP} +

This check flags all pseudo-random number engines, engine adaptor instantiations and srand() when initialized or seeded with default argument, constant expression or any user-configurable type. Pseudo-random number engines seeded with a predictable value may cause vulnerabilities e.g. in security protocols. This is a CERT security rule, see MSC51-CPP. Ensure your random number generator is properly seeded and MSC32-C. Properly seed pseudorandom number generators.

+

Examples:

+
void foo() {
+  std::mt19937 engine1; // Diagnose, always generate the same sequence
+  std::mt19937 engine2(1); // Diagnose
+  engine1.seed(); // Diagnose
+  engine2.seed(1); // Diagnose
+
+  std::time_t t;
+  engine1.seed(std::time(&t)); // Diagnose, system time might be controlled by user
+
+  int x = atoi(argv[1]);
+  std::mt19937 engine3(x);  // Will not warn
+}
+
Options
+

DisallowedSeedTypes

+

A comma-separated list of the type names which are disallowed. Default values are time_t, std::time_t.

+

(Clang-Tidy original name: cert-msc51-cpp)

+ + +#### Oop11 Cpp {#CT_CRT_OOP11_CPP} +

The cert-oop11-cpp check is an alias, please see performance-move-constructor-init for more information.

+

This check corresponds to the CERT C++ Coding Standard recommendation OOP11-CPP. Do not copy-initialize members or base classes from a move constructor. However, all of the CERT recommendations have been removed from public view, and so their justification for the behavior of this check requires an account on their wiki to view.

+

(Clang-Tidy original name: cert-oop11-cpp)

+ + +#### Oop54 Cpp {#CT_CRT_OOP54_CPP} +

The cert-oop54-cpp check is an alias, please see bugprone-unhandled-self-assignment for more information.

+

(Clang-Tidy original name: cert-oop54-cpp)

+ + +#### Oop57 Cpp {#CT_CRT_OOP57_CPP} +

Flags use of the C standard library functions memset, memcpy and memcmp and similar derivatives on non-trivial types.

+
Options
+

MemSetNames

+

Specify extra functions to flag that act similarily to memset. Specify names in a semicolon delimited list. Default is an empty string. The check will detect the following functions: memset, std::memset.

+

MemCpyNames

+

Specify extra functions to flag that act similarily to memcpy. Specify names in a semicolon delimited list. Default is an empty string. The check will detect the following functions: std::memcpy, memcpy, std::memmove, memmove, std::strcpy, strcpy, memccpy, stpncpy, strncpy.

+

MemCmpNames

+

Specify extra functions to flag that act similarily to memcmp. Specify names in a semicolon delimited list. Default is an empty string. The check will detect the following functions: std::memcmp, memcmp, std::strcmp, strcmp, strncmp.

+

This check corresponds to the CERT C++ Coding Standard rule OOP57-CPP. Prefer special member functions and overloaded operators to C Standard Library functions.

+

(Clang-Tidy original name: cert-oop57-cpp)

+ + +#### Oop58 Cpp {#CT_CRT_OOP58_CPP} +

Finds assignments to the copied object and its direct or indirect members in copy constructors and copy assignment operators.

+

This check corresponds to the CERT C Coding Standard rule OOP58-CPP. Copy operations must not mutate the source object.

+

(Clang-Tidy original name: cert-oop58-cpp)

+ + +#### Pos44 C {#CT_CRT_POS44_C} +

The cert-pos44-c check is an alias, please see bugprone-bad-signal-to-kill-thread for more information.

+

(Clang-Tidy original name: cert-pos44-c)

+ + +#### Sig30 C {#CT_CRT_SIG30_C} +

The cert-sig30-c check is an alias, please see bugprone-signal-handler for more information.

+

(Clang-Tidy original name: cert-sig30-c)

+ + +#### Str34 C {#CT_CRT_STR34_C} +

The cert-str34-c check is an alias, please see bugprone-signed-char-misuse for more information.

+

(Clang-Tidy original name: cert-str34-c)

+ + +### Concurrency + +#### Mt Unsafe {#CT_CON_MU} +

Checks for some thread-unsafe functions against a black list of known-to-be-unsafe functions. Usually they access static variables without synchronization (e.g. gmtime(3)) or utilize signals in a racy way. The set of functions to check is specified with the FunctionSet option.

+

Note that using some thread-unsafe functions may be still valid in concurrent programming if only a single thread is used (e.g. setenv(3)), however, some functions may track a state in global variables which would be clobbered by subsequent (non-parallel, but concurrent) calls to a related function. E.g. the following code suffers from unprotected accesses to a global state:

+
// getnetent(3) maintains global state with DB connection, etc.
+// If a concurrent green thread calls getnetent(3), the global state is corrupted.
+netent = getnetent();
+yield();
+netent = getnetent();
+

Examples:

+
tm = gmtime(timep); // uses a global buffer
+
+sleep(1); // implementation may use SIGALRM
+

FunctionSet

+

Specifies which functions in libc should be considered thread-safe, possible values are posix, glibc, or any.

+

posix means POSIX defined thread-unsafe functions. POSIX.1-2001 in “2.9.1 Thread-Safety” defines that all functions specified in the standard are thread-safe except a predefined list of thread-unsafe functions.

+

Glibc defines some of them as thread-safe (e.g. dirname(3)), but adds non-POSIX thread-unsafe ones (e.g. getopt_long(3)). Glibc’s list is compiled from GNU web documentation with a search for MT-Safe tag: https://www.gnu.org/software/libc/manual/html_node/POSIX-Safety-Concepts.html

+

If you want to identify thread-unsafe API for at least one libc or unsure which libc will be used, use any (default).

+

(Clang-Tidy original name: concurrency-mt-unsafe)

+ + +### Darwin + +#### Avoid Spinlock {#CT_DRW_AS} +

Finds usages of OSSpinlock, which is deprecated due to potential livelock problems.

+

This check will detect following function invocations:

+
    +
  • OSSpinlockLock
  • +
  • OSSpinlockTry
  • +
  • OSSpinlockUnlock
  • +
+

The corresponding information about the problem of OSSpinlock: https://blog.postmates.com/why-spinlocks-are-bad-on-ios-b69fc5221058

+

(Clang-Tidy original name: darwin-avoid-spinlock)

+ + +#### Dispatch Once Nonstatic {#CT_DRW_DON} +

Finds declarations of dispatch_once_t variables without static or global storage. The behavior of using dispatch_once_t predicates with automatic or dynamic storage is undefined by libdispatch, and should be avoided.

+

It is a common pattern to have functions initialize internal static or global data once when the function runs, but programmers have been known to miss the static on the dispatch_once_t predicate, leading to an uninitialized flag value at the mercy of the stack.

+

Programmers have also been known to make dispatch_once_t variables be members of structs or classes, with the intent to lazily perform some expensive struct or class member initialization only once; however, this violates the libdispatch requirements.

+

See the discussion section of Apple’s dispatch_once documentation for more information.

+

(Clang-Tidy original name: darwin-dispatch-once-nonstatic)

+ + +### Fuchsia + +#### Default Arguments Calls {#CT_FCS_DAC} +

Warns if a function or method is called with default arguments.

+

For example, given the declaration:

+
int foo(int value = 5) { return value; }
+

A function call expression that uses a default argument will be diagnosed. Calling it without defaults will not cause a warning:

+
foo();  // warning
+foo(0); // no warning
+

See the features disallowed in Fuchsia at https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md

+

(Clang-Tidy original name: fuchsia-default-arguments-calls)

+ + +#### Default Arguments Declarations {#CT_FCS_DAD} +

Warns if a function or method is declared with default parameters.

+

For example, the declaration:

+
int foo(int value = 5) { return value; }
+

will cause a warning.

+

See the features disallowed in Fuchsia at https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md

+

(Clang-Tidy original name: fuchsia-default-arguments-declarations)

+ + +#### Header Anon Namespaces {#CT_FCS_HAN} +

The fuchsia-header-anon-namespaces check is an alias, please see google-build-namespace for more information.

+

(Clang-Tidy original name: fuchsia-header-anon-namespaces)

+ + +#### Multiple Inheritance {#CT_FCS_MI} +

Warns if a class inherits from multiple classes that are not pure virtual.

+

For example, declaring a class that inherits from multiple concrete classes is disallowed:

+
class Base_A {
+public:
+  virtual int foo() { return 0; }
+};
+
+class Base_B {
+public:
+  virtual int bar() { return 0; }
+};
+
+// Warning
+class Bad_Child1 : public Base_A, Base_B {};
+

A class that inherits from a pure virtual is allowed:

+
class Interface_A {
+public:
+  virtual int foo() = 0;
+};
+
+class Interface_B {
+public:
+  virtual int bar() = 0;
+};
+
+// No warning
+class Good_Child1 : public Interface_A, Interface_B {
+  virtual int foo() override { return 0; }
+  virtual int bar() override { return 0; }
+};
+

See the features disallowed in Fuchsia at https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md

+

(Clang-Tidy original name: fuchsia-multiple-inheritance)

+ + +#### Overloaded Operator {#CT_FCS_OO} +

Warns if an operator is overloaded, except for the assignment (copy and move) operators.

+

For example:

+
int operator+(int);     // Warning
+
+B &operator=(const B &Other);  // No warning
+B &operator=(B &&Other) // No warning
+

See the features disallowed in Fuchsia at https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md

+

(Clang-Tidy original name: fuchsia-overloaded-operator)

+ + +#### Statically Constructed Objects {#CT_FCS_SCO} +

Warns if global, non-trivial objects with static storage are constructed, unless the object is statically initialized with a constexpr constructor or has no explicit constructor.

+

For example:

+
class A {};
+
+class B {
+public:
+  B(int Val) : Val(Val) {}
+private:
+  int Val;
+};
+
+class C {
+public:
+  C(int Val) : Val(Val) {}
+  constexpr C() : Val(0) {}
+
+private:
+  int Val;
+};
+
+static A a;         // No warning, as there is no explicit constructor
+static C c(0);      // No warning, as constructor is constexpr
+
+static B b(0);      // Warning, as constructor is not constexpr
+static C c2(0, 1);  // Warning, as constructor is not constexpr
+
+static int i;       // No warning, as it is trivial
+
+extern int get_i();
+static C(get_i())   // Warning, as the constructor is dynamically initialized
+

See the features disallowed in Fuchsia at https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md

+

(Clang-Tidy original name: fuchsia-statically-constructed-objects)

+ + +#### Trailing Return {#CT_FCS_TR} +

Functions that have trailing returns are disallowed, except for those using decltype specifiers and lambda with otherwise unutterable return types.

+

For example:

+
// No warning
+int add_one(const int arg) { return arg; }
+
+// Warning
+auto get_add_one() -> int (*)(const int) {
+  return add_one;
+}
+

Exceptions are made for lambdas and decltype specifiers:

+
// No warning
+auto lambda = [](double x, double y) -> double {return x + y;};
+
+// No warning
+template <typename T1, typename T2>
+auto fn(const T1 &lhs, const T2 &rhs) -> decltype(lhs + rhs) {
+  return lhs + rhs;
+}
+

See the features disallowed in Fuchsia at https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md

+

(Clang-Tidy original name: fuchsia-trailing-return)

+ + +#### Virtual Inheritance {#CT_FCS_VI} +

Warns if classes are defined with virtual inheritance.

+

For example, classes should not be defined with virtual inheritance:

+
class B : public virtual A {};   // warning
+

See the features disallowed in Fuchsia at https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md

+

(Clang-Tidy original name: fuchsia-virtual-inheritance)

+ + +### Google + +#### Build Explicit Make Pair {#CT_GGL_BEMP} +

Check that make_pair’s template arguments are deduced.

+

G++ 4.6 in C++11 mode fails badly if make_pair’s template arguments are specified explicitly, and such use isn’t intended in any case.

+

Corresponding cpplint.py check name: build/explicit_make_pair.

+

(Clang-Tidy original name: google-build-explicit-make-pair)

+ + +#### Build Namespaces {#CT_GGL_BN} +

cert-dcl59-cpp redirects here as an alias for this check. fuchsia-header-anon-namespaces redirects here as an alias for this check.

+

Finds anonymous namespaces in headers.

+

https://google.github.io/styleguide/cppguide.html\#Namespaces

+

Corresponding cpplint.py check name: build/namespaces.

+
Options
+

HeaderFileExtensions

+

A comma-separated list of filename extensions of header files (the filename extensions should not include “.” prefix). Default is “h,hh,hpp,hxx”. For header files without an extension, use an empty string (if there are no other desired extensions) or leave an empty element in the list. e.g., “h,hh,hpp,hxx,” (note the trailing comma).

+

(Clang-Tidy original name: google-build-namespaces)

+ + +#### Build Using Namespace {#CT_GGL_BUN} +

Finds using namespace directives.

+

The check implements the following rule of the Google C++ Style Guide:

+

You may not use a using-directive to make all names from a namespace available.

+
// Forbidden -- This pollutes the namespace.
+using namespace foo;
+

Corresponding cpplint.py check name: build/namespaces.

+

(Clang-Tidy original name: google-build-using-namespace)

+ + +#### Default Arguments {#CT_GGL_DA} +

Checks that default arguments are not given for virtual methods.

+

See https://google.github.io/styleguide/cppguide.html\#Default_Arguments

+

(Clang-Tidy original name: google-default-arguments)

+ + +#### Explicit Constructor {#CT_GGL_EC} +

Checks that constructors callable with a single argument and conversion operators are marked explicit to avoid the risk of unintentional implicit conversions.

+

Consider this example:

+
struct S {
+  int x;
+  operator bool() const { return true; }
+};
+
+bool f() {
+  S a{1};
+  S b{2};
+  return a == b;
+}
+

The function will return true, since the objects are implicitly converted to bool before comparison, which is unlikely to be the intent.

+

The check will suggest inserting explicit before the constructor or conversion operator declaration. However, copy and move constructors should not be explicit, as well as constructors taking a single initializer_list argument.

+

This code:

+
struct S {
+  S(int a);
+  explicit S(const S&);
+  operator bool() const;
+  ...
+

will become

+
struct S {
+  explicit S(int a);
+  S(const S&);
+  explicit operator bool() const;
+  ...
+

See https://google.github.io/styleguide/cppguide.html\#Explicit_Constructors

+

(Clang-Tidy original name: google-explicit-constructor)

+ + +#### Global Names In Headers {#CT_GGL_GNIH} +

Flag global namespace pollution in header files. Right now it only triggers on using declarations and directives.

+

The relevant style guide section is https://google.github.io/styleguide/cppguide.html\#Namespaces.

+
Options
+

HeaderFileExtensions

+

A comma-separated list of filename extensions of header files (the filename extensions should not contain “.” prefix). Default is “h”. For header files without an extension, use an empty string (if there are no other desired extensions) or leave an empty element in the list. e.g., “h,hh,hpp,hxx,” (note the trailing comma).

+

(Clang-Tidy original name: google-global-names-in-headers)

+ + +#### Objc Avoid Nsobject New {#CT_GGL_OANN} +

Finds calls to +new or overrides of it, which are prohibited by the Google Objective-C style guide.

+

The Google Objective-C style guide forbids calling +new or overriding it in class implementations, preferring +alloc and -init methods to instantiate objects.

+

An example:

+
NSDate *now = [NSDate new];
+Foo *bar = [Foo new];
+

Instead, code should use +alloc/-init or class factory methods.

+
NSDate *now = [NSDate date];
+Foo *bar = [[Foo alloc] init];
+

This check corresponds to the Google Objective-C Style Guide rule Do Not Use +new.

+

(Clang-Tidy original name: google-objc-avoid-nsobject-new)

+ + +#### Objc Avoid Throwing Exception {#CT_GGL_OATE} +

Finds uses of throwing exceptions usages in Objective-C files.

+

For the same reason as the Google C++ style guide, we prefer not throwing exceptions from Objective-C code.

+

The corresponding C++ style guide rule: https://google.github.io/styleguide/cppguide.html\#Exceptions

+

Instead, prefer passing in NSError ** and return BOOL to indicate success or failure.

+

A counterexample:

+
- (void)readFile {
+  if ([self isError]) {
+    @throw [NSException exceptionWithName:...];
+  }
+}
+

Instead, returning an error via NSError ** is preferred:

+
- (BOOL)readFileWithError:(NSError **)error {
+  if ([self isError]) {
+    *error = [NSError errorWithDomain:...];
+    return NO;
+  }
+  return YES;
+}
+

The corresponding style guide rule: https://google.github.io/styleguide/objcguide.html\#avoid-throwing-exceptions

+

(Clang-Tidy original name: google-objc-avoid-throwing-exception)

+ + +#### Objc Function Naming {#CT_GGL_OFN} +

Finds function declarations in Objective-C files that do not follow the pattern described in the Google Objective-C Style Guide.

+

The corresponding style guide rule can be found here: https://google.github.io/styleguide/objcguide.html\#function-names

+

All function names should be in Pascal case. Functions whose storage class is not static should have an appropriate prefix.

+

The following code sample does not follow this pattern:

+
static bool is_positive(int i) { return i > 0; }
+bool IsNegative(int i) { return i < 0; }
+

The sample above might be corrected to the following code:

+
static bool IsPositive(int i) { return i > 0; }
+bool *ABCIsNegative(int i) { return i < 0; }
+

(Clang-Tidy original name: google-objc-function-naming)

+ + +#### Objc Global Variable Declaration {#CT_GGL_OGVD} +

Finds global variable declarations in Objective-C files that do not follow the pattern of variable names in Google’s Objective-C Style Guide.

+

The corresponding style guide rule: https://google.github.io/styleguide/objcguide.html\#variable-names

+

All the global variables should follow the pattern of g[A-Z].* (variables) or k[A-Z].* (constants). The check will suggest a variable name that follows the pattern if it can be inferred from the original name.

+

For code:

+
static NSString* myString = @"hello";
+

The fix will be:

+
static NSString* gMyString = @"hello";
+

Another example of constant:

+
static NSString* const myConstString = @"hello";
+

The fix will be:

+
static NSString* const kMyConstString = @"hello";
+

However for code that prefixed with non-alphabetical characters like:

+
static NSString* __anotherString = @"world";
+

The check will give a warning message but will not be able to suggest a fix. The user needs to fix it on their own.

+

(Clang-Tidy original name: google-objc-global-variable-declaration)

+ + +#### Readability Avoid Underscore In Googletest Name {#CT_GGL_RAUIGN} +

Checks whether there are underscores in googletest test and test case names in test macros:

+
    +
  • TEST
  • +
  • TEST_F
  • +
  • TEST_P
  • +
  • TYPED_TEST
  • +
  • TYPED_TEST_P
  • +
+

The FRIEND_TEST macro is not included.

+

For example:

+
TEST(TestCaseName, Illegal_TestName) {}
+TEST(Illegal_TestCaseName, TestName) {}
+

would trigger the check. Underscores are not allowed in test names nor test case names.

+

The DISABLED_ prefix, which may be used to disable individual tests, is ignored when checking test names, but the rest of the rest of the test name is still checked.

+

This check does not propose any fixes.

+

(Clang-Tidy original name: google-readability-avoid-underscore-in-googletest-name)

+ + +#### Readability Braces Around Statements {#CT_GGL_RBAS} +

The google-readability-braces-around-statements check is an alias, please see readability-braces-around-statements for more information.

+

(Clang-Tidy original name: google-readability-braces-around-statements)

+ + +#### Readability Casting {#CT_GGL_RC} +

Finds usages of C-style casts.

+

https://google.github.io/styleguide/cppguide.html\#Casting

+

Corresponding cpplint.py check name: readability/casting.

+

This check is similar to -Wold-style-cast, but it suggests automated fixes in some cases. The reported locations should not be different from the ones generated by -Wold-style-cast.

+

(Clang-Tidy original name: google-readability-casting)

+ + +#### Readability Function Size {#CT_GGL_RFS} +

The google-readability-function-size check is an alias, please see readability-function-size for more information.

+

(Clang-Tidy original name: google-readability-function-size)

+ + +#### Readability Namespace Comments {#CT_GGL_RNC} +

The google-readability-namespace-comments check is an alias, please see llvm-namespace-comment for more information.

+

(Clang-Tidy original name: google-readability-namespace-comments)

+ + +#### Readability Todo {#CT_GGL_RT} +

Finds TODO comments without a username or bug number.

+

The relevant style guide section is https://google.github.io/styleguide/cppguide.html\#TODO_Comments.

+

Corresponding cpplint.py check: readability/todo

+

(Clang-Tidy original name: google-readability-todo)

+ + +#### Runtime Int {#CT_GGL_RI} +

Finds uses of short, long and long long and suggest replacing them with u?intXX(_t)?.

+

The corresponding style guide rule: https://google.github.io/styleguide/cppguide.html\#Integer_Types.

+

Corresponding cpplint.py check: runtime/int.

+
Options
+

UnsignedTypePrefix

+

A string specifying the unsigned type prefix. Default is uint.

+

SignedTypePrefix

+

A string specifying the signed type prefix. Default is int.

+

TypeSuffix

+

A string specifying the type suffix. Default is an empty string.

+

(Clang-Tidy original name: google-runtime-int)

+ + +#### Runtime Operator {#CT_GGL_RO} +

Finds overloads of unary operator &.

+

https://google.github.io/styleguide/cppguide.html\#Operator_Overloading

+

Corresponding cpplint.py check name: runtime/operator.

+

(Clang-Tidy original name: google-runtime-operator)

+ + +#### Upgrade Googletest Case {#CT_GGL_UGC} +

Finds uses of deprecated Google Test version 1.9 APIs with names containing case and replaces them with equivalent APIs with suite.

+

All names containing case are being replaced to be consistent with the meanings of “test case” and “test suite” as used by the International Software Testing Qualifications Board and ISO 29119.

+

The new names are a part of Google Test version 1.9 (release pending). It is recommended that users update their dependency to version 1.9 and then use this check to remove deprecated names.

+

The affected APIs are:

+
    +
  • Member functions of testing::Test, testing::TestInfo, testing::TestEventListener, testing::UnitTest, and any type inheriting from these types
  • +
  • The macros TYPED_TEST_CASE, TYPED_TEST_CASE_P, REGISTER_TYPED_TEST_CASE_P, and INSTANTIATE_TYPED_TEST_CASE_P
  • +
  • The type alias testing::TestCase
  • +
+

Examples of fixes created by this check:

+
class FooTest : public testing::Test {
+public:
+  static void SetUpTestCase();
+  static void TearDownTestCase();
+};
+
+TYPED_TEST_CASE(BarTest, BarTypes);
+

becomes

+
class FooTest : public testing::Test {
+public:
+  static void SetUpTestSuite();
+  static void TearDownTestSuite();
+};
+
+TYPED_TEST_SUITE(BarTest, BarTypes);
+

For better consistency of user code, the check renames both virtual and non-virtual member functions with matching names in derived types. The check tries to provide a only warning when a fix cannot be made safely, as is the case with some template and macro uses.

+

(Clang-Tidy original name: google-upgrade-googletest-case)

+ + +### High Integrity C++ + +#### Avoid C Arrays {#CT_HIC_ACA} +

The hicpp-avoid-c-arrays check is an alias, please see modernize-avoid-c-arrays for more information.

+

(Clang-Tidy original name: hicpp-avoid-c-arrays)

+ + +#### Avoid Goto {#CT_HIC_AG} +

The hicpp-avoid-goto check is an alias to cppcoreguidelines-avoid-goto. Rule 6.3.1 High Integrity C++ requires that goto only skips parts of a block and is not used for other reasons.

+

Both coding guidelines implement the same exception to the usage of goto.

+

(Clang-Tidy original name: hicpp-avoid-goto)

+ + +#### Braces Around Statements {#CT_HIC_BAS} +

The hicpp-braces-around-statements check is an alias, please see readability-braces-around-statements for more information. It enforces the rule 6.1.1.

+

(Clang-Tidy original name: hicpp-braces-around-statements)

+ + +#### Deprecated Headers {#CT_HIC_DH} +

The hicpp-deprecated-headers check is an alias, please see modernize-deprecated-headers for more information. It enforces the rule 1.3.3.

+

(Clang-Tidy original name: hicpp-deprecated-headers)

+ + +#### Exception Baseclass {#CT_HIC_EB} +

Ensure that every value that in a throw expression is an instance of std::exception.

+

This enforces rule 15.1 of the High Integrity C++ Coding Standard.

+
class custom_exception {};
+
+void throwing() noexcept(false) {
+  // Problematic throw expressions.
+  throw int(42);
+  throw custom_exception();
+}
+
+class mathematical_error : public std::exception {};
+
+void throwing2() noexcept(false) {
+  // These kind of throws are ok.
+  throw mathematical_error();
+  throw std::runtime_error();
+  throw std::exception();
+}
+

(Clang-Tidy original name: hicpp-exception-baseclass)

+ + +#### Explicit Conversions {#CT_HIC_EC} +

This check is an alias for google-explicit-constructor. Used to enforce parts of rule 5.4.1. This check will enforce that constructors and conversion operators are marked explicit. Other forms of casting checks are implemented in other places. The following checks can be used to check for more forms of casting:

+ +

(Clang-Tidy original name: hicpp-explicit-conversions)

+ + +#### Function Size {#CT_HIC_FS} +

This check is an alias for readability-function-size. Useful to enforce multiple sections on function complexity.

+ +

(Clang-Tidy original name: hicpp-function-size)

+ + +#### Invalid Access Moved {#CT_HIC_IAM} +

This check is an alias for bugprone-use-after-move.

+

Implements parts of the rule 8.4.1 to check if moved-from objects are accessed.

+

(Clang-Tidy original name: hicpp-invalid-access-moved)

+ + +#### Member Init {#CT_HIC_MI} +

This check is an alias for cppcoreguidelines-pro-type-member-init. Implements the check for rule 12.4.2 to initialize class members in the right order.

+

(Clang-Tidy original name: hicpp-member-init)

+ + +#### Move Const Arg {#CT_HIC_MCA} +

The hicpp-move-const-arg check is an alias, please see performance-move-const-arg for more information. It enforces the rule 17.3.1.

+

(Clang-Tidy original name: hicpp-move-const-arg)

+ + +#### Multiway Paths Covered {#CT_HIC_MPC} +

This check discovers situations where code paths are not fully-covered. It furthermore suggests using if instead of switch if the code will be more clear. The rule 6.1.2 and rule 6.1.4 of the High Integrity C++ Coding Standard are enforced.

+

if-else if chains that miss a final else branch might lead to unexpected program execution and be the result of a logical error. If the missing else branch is intended you can leave it empty with a clarifying comment. This warning can be noisy on some code bases, so it is disabled by default.

+
void f1() {
+  int i = determineTheNumber();
+
+   if(i > 0) {
+     // Some Calculation
+   } else if (i < 0) {
+     // Precondition violated or something else.
+   }
+   // ...
+}
+

Similar arguments hold for switch statements which do not cover all possible code paths.

+
// The missing default branch might be a logical error. It can be kept empty
+// if there is nothing to do, making it explicit.
+void f2(int i) {
+  switch (i) {
+  case 0: // something
+    break;
+  case 1: // something else
+    break;
+  }
+  // All other numbers?
+}
+
+// Violates this rule as well, but already emits a compiler warning (-Wswitch).
+enum Color { Red, Green, Blue, Yellow };
+void f3(enum Color c) {
+  switch (c) {
+  case Red: // We can't drive for now.
+    break;
+  case Green:  // We are allowed to drive.
+    break;
+  }
+  // Other cases missing
+}
+

The rule 6.1.4 requires every switch statement to have at least two case labels other than a default label. Otherwise, the switch could be better expressed with an if statement. Degenerated switch statements without any labels are caught as well.

+
// Degenerated switch that could be better written as `if`
+int i = 42;
+switch(i) {
+  case 1: // do something here
+  default: // do somethe else here
+}
+
+// Should rather be the following:
+if (i == 1) {
+  // do something here
+}
+else {
+  // do something here
+}
+
// A completely degenerated switch will be diagnosed.
+int i = 42;
+switch(i) {}
+
Options
+

WarnOnMissingElse

+

Boolean flag that activates a warning for missing else branches. Default is false.

+

(Clang-Tidy original name: hicpp-multiway-paths-covered)

+ + +#### Named Parameter {#CT_HIC_NP} +

This check is an alias for readability-named-parameter.

+

Implements rule 8.2.1.

+

(Clang-Tidy original name: hicpp-named-parameter)

+ + +#### New Delete Operators {#CT_HIC_NDO} +

This check is an alias for misc-new-delete-overloads. Implements rule 12.3.1 to ensure the new and delete operators have the correct signature.

+

(Clang-Tidy original name: hicpp-new-delete-operators)

+ + +#### No Array Decay {#CT_HIC_NAD} +

The hicpp-no-array-decay check is an alias, please see cppcoreguidelines-pro-bounds-array-to-pointer-decay for more information. It enforces the rule 4.1.1.

+

(Clang-Tidy original name: hicpp-no-array-decay)

+ + +#### No Assembler {#CT_HIC_NA} +

Check for assembler statements. No fix is offered.

+

Inline assembler is forbidden by the High Intergrity C++ Coding Standard as it restricts the portability of code.

+

(Clang-Tidy original name: hicpp-no-assembler)

+ + +#### No Malloc {#CT_HIC_NM2} +

The hicpp-no-malloc check is an alias, please see cppcoreguidelines-no-malloc for more information. It enforces the rule 5.3.2.

+

(Clang-Tidy original name: hicpp-no-malloc)

+ + +#### Noexcept Move {#CT_HIC_NM} +

This check is an alias for performance-noexcept-move-constructor. Checks rule 12.5.4 to mark move assignment and move construction noexcept.

+

(Clang-Tidy original name: hicpp-noexcept-move)

+ + +#### Signed Bitwise {#CT_HIC_SB} +

Finds uses of bitwise operations on signed integer types, which may lead to undefined or implementation defined behaviour.

+

The according rule is defined in the High Integrity C++ Standard, Section 5.6.1.

+
Options
+

IgnorePositiveIntegerLiterals

+

If this option is set to true, the check will not warn on bitwise operations with positive integer literals, e.g. ~0, 2 << 1, etc. Default value is false.

+

(Clang-Tidy original name: hicpp-signed-bitwise)

+ + +#### Special Member Functions {#CT_HIC_SMF} +

This check is an alias for cppcoreguidelines-special-member-functions. Checks that special member functions have the correct signature, according to rule 12.5.7.

+

(Clang-Tidy original name: hicpp-special-member-functions)

+ + +#### Static Assert {#CT_HIC_SA} +

The hicpp-static-assert check is an alias, please see misc-static-assert for more information. It enforces the rule 7.1.10.

+

(Clang-Tidy original name: hicpp-static-assert)

+ + +#### Undelegated Constructor {#CT_HIC_UC} +

This check is an alias for bugprone-undelegated-constructor. Partially implements rule 12.4.5 to find misplaced constructor calls inside a constructor.

+
struct Ctor {
+  Ctor();
+  Ctor(int);
+  Ctor(int, int);
+  Ctor(Ctor *i) {
+    // All Ctor() calls result in a temporary object
+    Ctor(); // did you intend to call a delegated constructor?
+    Ctor(0); // did you intend to call a delegated constructor?
+    Ctor(1, 2); // did you intend to call a delegated constructor?
+    foo();
+  }
+};
+

(Clang-Tidy original name: hicpp-undelegated-constructor)

+ + +#### Uppercase Literal Suffix {#CT_HIC_ULS} +

The hicpp-uppercase-literal-suffix check is an alias, please see readability-uppercase-literal-suffix for more information.

+

(Clang-Tidy original name: hicpp-uppercase-literal-suffix)

+ + +#### Use Auto {#CT_HIC_UA} +

The hicpp-use-auto check is an alias, please see modernize-use-auto for more information. It enforces the rule 7.1.8.

+

(Clang-Tidy original name: hicpp-use-auto)

+ + +#### Use Emplace {#CT_HIC_UE} +

The hicpp-use-emplace check is an alias, please see modernize-use-emplace for more information. It enforces the rule 17.4.2.

+

(Clang-Tidy original name: hicpp-use-emplace)

+ + +#### Use Equals Default {#CT_HIC_UED} +

This check is an alias for modernize-use-equals-default. Implements rule 12.5.1 to explicitly default special member functions.

+

(Clang-Tidy original name: hicpp-use-equals-default)

+ + +#### Use Equals Delete {#CT_HIC_UED2} +

This check is an alias for modernize-use-equals-delete. Implements rule 12.5.1 to explicitly default or delete special member functions.

+

(Clang-Tidy original name: hicpp-use-equals-delete)

+ + +#### Use Noexcept {#CT_HIC_UN} +

The hicpp-use-noexcept check is an alias, please see modernize-use-noexcept for more information. It enforces the rule 1.3.5.

+

(Clang-Tidy original name: hicpp-use-noexcept)

+ + +#### Use Nullptr {#CT_HIC_UN2} +

The hicpp-use-nullptr check is an alias, please see modernize-use-nullptr for more information. It enforces the rule 2.5.3.

+

(Clang-Tidy original name: hicpp-use-nullptr)

+ + +#### Use Override {#CT_HIC_UO} +

This check is an alias for modernize-use-override. Implements rule 10.2.1 to declare a virtual function override when overriding.

+

(Clang-Tidy original name: hicpp-use-override)

+ + +#### Vararg {#CT_HIC_V} +

The hicpp-vararg check is an alias, please see cppcoreguidelines-pro-type-vararg for more information. It enforces the rule 14.1.1.

+

(Clang-Tidy original name: hicpp-vararg)

+ + +### LLVM + +#### Else After Return {#CT_LLV_EAR} +

The llvm-else-after-return check is an alias, please see readability-else-after-return for more information.

+

(Clang-Tidy original name: llvm-else-after-return)

+ + +#### Header Guard {#CT_LLV_HG} +

Finds and fixes header guards that do not adhere to LLVM style.

+
Options
+

HeaderFileExtensions

+

A comma-separated list of filename extensions of header files (the filename extensions should not include “.” prefix). Default is “h,hh,hpp,hxx”. For header files without an extension, use an empty string (if there are no other desired extensions) or leave an empty element in the list. e.g., “h,hh,hpp,hxx,” (note the trailing comma).

+

(Clang-Tidy original name: llvm-header-guard)

+ + +#### Include Order {#CT_LLV_IO} +

Checks the correct order of #includes.

+

See https://llvm.org/docs/CodingStandards.html\#include-style

+

(Clang-Tidy original name: llvm-include-order)

+ + +#### Namespace Comment {#CT_LLV_NC} +

google-readability-namespace-comments redirects here as an alias for this check.

+

Checks that long namespaces have a closing comment.

+

https://llvm.org/docs/CodingStandards.html\#namespace-indentation

+

https://google.github.io/styleguide/cppguide.html\#Namespaces

+
namespace n1 {
+void f();
+}
+
+// becomes
+
+namespace n1 {
+void f();
+}  // namespace n1
+
Options
+

ShortNamespaceLines

+

Requires the closing brace of the namespace definition to be followed by a closing comment if the body of the namespace has more than ShortNamespaceLines lines of code. The value is an unsigned integer that defaults to 1U.

+

SpacesBeforeComments

+

An unsigned integer specifying the number of spaces before the comment closing a namespace definition. Default is 1U.

+

(Clang-Tidy original name: llvm-namespace-comment)

+ + +#### Prefer Isa Or Dyn Cast In Conditionals {#CT_LLV_PIODCIC} +

Looks at conditionals and finds and replaces cases of cast<>, which will assert rather than return a null pointer, and dyn_cast<> where the return value is not captured. Additionally, finds and replaces cases that match the pattern var && isa(var), where var is evaluated twice.

+
// Finds these:
+if (auto x = cast<X>(y)) {}
+// is replaced by:
+if (auto x = dyn_cast<X>(y)) {}
+
+if (cast<X>(y)) {}
+// is replaced by:
+if (isa<X>(y)) {}
+
+if (dyn_cast<X>(y)) {}
+// is replaced by:
+if (isa<X>(y)) {}
+
+if (var && isa<T>(var)) {}
+// is replaced by:
+if (isa_and_nonnull<T>(var.foo())) {}
+
+// Other cases are ignored, e.g.:
+if (auto f = cast<Z>(y)->foo()) {}
+if (cast<Z>(y)->foo()) {}
+if (X.cast(y)) {}
+

(Clang-Tidy original name: llvm-prefer-isa-or-dyn-cast-in-conditionals)

+ + +#### Prefer Register Over Unsigned {#CT_LLV_PROU} +

Finds historical use of unsigned to hold vregs and physregs and rewrites them to use Register.

+

Currently this works by finding all variables of unsigned integer type whose initializer begins with an implicit cast from Register to unsigned.

+
void example(MachineOperand &MO) {
+  unsigned Reg = MO.getReg();
+  ...
+}
+

becomes:

+
void example(MachineOperand &MO) {
+  Register Reg = MO.getReg();
+  ...
+}
+

(Clang-Tidy original name: llvm-prefer-register-over-unsigned)

+ + +#### Qualified Auto {#CT_LLV_QA} +

The llvm-qualified-auto check is an alias, please see readability-qualified-auto for more information.

+

(Clang-Tidy original name: llvm-qualified-auto)

+ + +#### Twine Local {#CT_LLV_TL} +

Looks for local Twine variables which are prone to use after frees and should be generally avoided.

+
static Twine Moo = Twine("bark") + "bah";
+
+// becomes
+
+static std::string Moo = (Twine("bark") + "bah").str();
+

(Clang-Tidy original name: llvm-twine-local)

+ + +### LLVM-libc + +#### Callee Namespace {#CT_LLC_CN} +

Checks all calls resolve to functions within __llvm_libc namespace.

+
namespace __llvm_libc {
+
+// Allow calls with the fully qualified name.
+__llvm_libc::strlen("hello");
+
+// Allow calls to compiler provided functions.
+(void)__builtin_abs(-1);
+
+// Bare calls are allowed as long as they resolve to the correct namespace.
+strlen("world");
+
+// Disallow calling into functions in the global namespace.
+::strlen("!");
+
+} // namespace __llvm_libc
+

(Clang-Tidy original name: llvmlibc-callee-namespace)

+ + +#### Implementation In Namespace {#CT_LLC_IIN} +

Checks that all declarations in the llvm-libc implementation are within the correct namespace.

+
// Correct: implementation inside the correct namespace.
+namespace __llvm_libc {
+    void LLVM_LIBC_ENTRYPOINT(strcpy)(char *dest, const char *src) {}
+    // Namespaces within __llvm_libc namespace are allowed.
+    namespace inner{
+        int localVar = 0;
+    }
+    // Functions with C linkage are allowed.
+    extern "C" void str_fuzz(){}
+}
+
+// Incorrect: implementation not in a namespace.
+void LLVM_LIBC_ENTRYPOINT(strcpy)(char *dest, const char *src) {}
+
+// Incorrect: outer most namespace is not correct.
+namespace something_else {
+    void LLVM_LIBC_ENTRYPOINT(strcpy)(char *dest, const char *src) {}
+}
+

(Clang-Tidy original name: llvmlibc-implementation-in-namespace)

+ + +#### Restrict System Libc Headers {#CT_LLC_RSLH} +

Finds includes of system libc headers not provided by the compiler within llvm-libc implementations.

+
#include <stdio.h>            // Not allowed because it is part of system libc.
+#include <stddef.h>           // Allowed because it is provided by the compiler.
+#include "internal/stdio.h"   // Allowed because it is NOT part of system libc.
+

This check is necessary because accidentally including system libc headers can lead to subtle and hard to detect bugs. For example consider a system libc whose dirent struct has slightly different field ordering than llvm-libc. While this will compile successfully, this can cause issues during runtime because they are ABI incompatible.

+
Options
+

Includes

+

A string containing a comma separated glob list of allowed include filenames. Similar to the -checks glob list for running clang-tidy itself, the two wildcard characters are * and -, to include and exclude globs, respectively. The default is -*, which disallows all includes.

+

This can be used to allow known safe includes such as Linux development headers. See portability-restrict-system-includes for more details.

+

(Clang-Tidy original name: llvmlibc-restrict-system-libc-headers)

+ + +### Linux Kernel + +#### Must Check Errs {#CT_KRN_MCE} +

Checks Linux kernel code to see if it uses the results from the functions in linux/err.h. Also checks to see if code uses the results from functions that directly return a value from one of these error functions.

+

This is important in the Linux kernel because ERR_PTR, PTR_ERR, IS_ERR, IS_ERR_OR_NULL, ERR_CAST, and PTR_ERR_OR_ZERO return values must be checked, since positive pointers and negative error codes are being used in the same context. These functions are marked with attribute((warn_unused_result)), but some kernel versions do not have this warning enabled for clang.

+

Examples:

+
/* Trivial unused call to an ERR function */
+PTR_ERR_OR_ZERO(some_function_call());
+
+/* A function that returns ERR_PTR. */
+void *fn() { ERR_PTR(-EINVAL); }
+
+/* An invalid use of fn. */
+fn();
+

(Clang-Tidy original name: linuxkernel-must-check-errs)

+ + +### MPI + +#### Buffer Deref {#CT_MPI_BD} +

This check verifies if a buffer passed to an MPI (Message Passing Interface) function is sufficiently dereferenced. Buffers should be passed as a single pointer or array. As MPI function signatures specify void * for their buffer types, insufficiently dereferenced buffers can be passed, like for example as double pointers or multidimensional arrays, without a compiler warning emitted.

+

Examples:

+
// A double pointer is passed to the MPI function.
+char *buf;
+MPI_Send(&buf, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+
+// A multidimensional array is passed to the MPI function.
+short buf[1][1];
+MPI_Send(buf, 1, MPI_SHORT, 0, 0, MPI_COMM_WORLD);
+
+// A pointer to an array is passed to the MPI function.
+short *buf[1];
+MPI_Send(buf, 1, MPI_SHORT, 0, 0, MPI_COMM_WORLD);
+

(Clang-Tidy original name: mpi-buffer-deref)

+ + +#### Type Mismatch {#CT_MPI_TM} +

This check verifies if buffer type and MPI (Message Passing Interface) datatype pairs match for used MPI functions. All MPI datatypes defined by the MPI standard (3.1) are verified by this check. User defined typedefs, custom MPI datatypes and null pointer constants are skipped, in the course of verification.

+

Example:

+
// In this case, the buffer type matches MPI datatype.
+char buf;
+MPI_Send(&buf, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+
+// In the following case, the buffer type does not match MPI datatype.
+int buf;
+MPI_Send(&buf, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+

(Clang-Tidy original name: mpi-type-mismatch)

+ + +### Miscellaneous + +#### Definitions In Headers {#CT_MSC_DIH} +

Finds non-extern non-inline function and variable definitions in header files, which can lead to potential ODR violations in case these headers are included from multiple translation units.

+
// Foo.h
+int a = 1; // Warning: variable definition.
+extern int d; // OK: extern variable.
+
+namespace N {
+  int e = 2; // Warning: variable definition.
+}
+
+// Warning: variable definition.
+const char* str = "foo";
+
+// OK: internal linkage variable definitions are ignored for now.
+// Although these might also cause ODR violations, we can be less certain and
+// should try to keep the false-positive rate down.
+static int b = 1;
+const int c = 1;
+const char* const str2 = "foo";
+constexpr int k = 1;
+
+// Warning: function definition.
+int g() {
+  return 1;
+}
+
+// OK: inline function definition is allowed to be defined multiple times.
+inline int e() {
+  return 1;
+}
+
+class A {
+public:
+  int f1() { return 1; } // OK: implicitly inline member function definition is allowed.
+  int f2();
+
+  static int d;
+};
+
+// Warning: not an inline member function definition.
+int A::f2() { return 1; }
+
+// OK: class static data member declaration is allowed.
+int A::d = 1;
+
+// OK: function template is allowed.
+template<typename T>
+T f3() {
+  T a = 1;
+  return a;
+}
+
+// Warning: full specialization of a function template is not allowed.
+template <>
+int f3() {
+  int a = 1;
+  return a;
+}
+
+template <typename T>
+struct B {
+  void f1();
+};
+
+// OK: member function definition of a class template is allowed.
+template <typename T>
+void B<T>::f1() {}
+
+class CE {
+  constexpr static int i = 5; // OK: inline variable definition.
+};
+
+inline int i = 5; // OK: inline variable definition.
+
+constexpr int f10() { return 0; } // OK: constexpr function implies inline.
+
+// OK: C++14 variable templates are inline.
+template <class T>
+constexpr T pi = T(3.1415926L);
+
Options
+

HeaderFileExtensions

+

A comma-separated list of filename extensions of header files (the filename extensions should not include “.” prefix). Default is “h,hh,hpp,hxx”. For header files without an extension, use an empty string (if there are no other desired extensions) or leave an empty element in the list. e.g., “h,hh,hpp,hxx,” (note the trailing comma).

+

UseHeaderFileExtension

+

When true, the check will use the file extension to distinguish header files. Default is true.

+

(Clang-Tidy original name: misc-definitions-in-headers)

+ + +#### Misplaced Const {#CT_MSC_MC} +

This check diagnoses when a const qualifier is applied to a typedef/ using to a pointer type rather than to the pointee, because such constructs are often misleading to developers because the const applies to the pointer rather than the pointee.

+

For instance, in the following code, the resulting type is int * const rather than const int *:

+
typedef int *int_ptr;
+void f(const int_ptr ptr) {
+  *ptr = 0; // potentially quite unexpectedly the int can be modified here
+  ptr = 0; // does not compile
+}
+

The check does not diagnose when the underlying typedef/using type is a pointer to a const type or a function pointer type. This is because the const qualifier is less likely to be mistaken because it would be redundant (or disallowed) on the underlying pointee type.

+

(Clang-Tidy original name: misc-misplaced-const)

+ + +#### New Delete Overloads {#CT_MSC_NDO} +

cert-dcl54-cpp redirects here as an alias for this check.

+

The check flags overloaded operator new() and operator delete() functions that do not have a corresponding free store function defined within the same scope. For instance, the check will flag a class implementation of a non-placement operator new() when the class does not also define a non-placement operator delete() function as well.

+

The check does not flag implicitly-defined operators, deleted or private operators, or placement operators.

+

This check corresponds to CERT C++ Coding Standard rule DCL54-CPP. Overload allocation and deallocation functions as a pair in the same scope.

+

(Clang-Tidy original name: misc-new-delete-overloads)

+ + +#### No Recursion {#CT_MSC_NR} +

Finds strongly connected functions (by analyzing the call graph for SCC’s (Strongly Connected Components) that are loops), diagnoses each function in the cycle, and displays one example of a possible call graph loop (recursion).

+

References:

+ +

Limitations:

+
    +
  • The check does not handle calls done through function pointers
  • +
  • The check does not handle C++ destructors
  • +
+

(Clang-Tidy original name: misc-no-recursion)

+ + +#### Non Copyable Objects {#CT_MSC_NCO} +

cert-fio38-c redirects here as an alias for this check.

+

The check flags dereferences and non-pointer declarations of objects that are not meant to be passed by value, such as C FILE objects or POSIX pthread_mutex_t objects.

+

This check corresponds to CERT C++ Coding Standard rule FIO38-C. Do not copy a FILE object.

+

(Clang-Tidy original name: misc-non-copyable-objects)

+ + +#### Non Private Member Variables In Classes {#CT_MSC_NPMVIC} +

cppcoreguidelines-non-private-member-variables-in-classes redirects here as an alias for this check.

+

Finds classes that contain non-static data members in addition to user-declared non-static member functions and diagnose all data members declared with a non-public access specifier. The data members should be declared as private and accessed through member functions instead of exposed to derived classes or class consumers.

+
Options
+

IgnoreClassesWithAllMemberVariablesBeingPublic

+

Allows to completely ignore classes if all the member variables in that class a declared with a public access specifier.

+

IgnorePublicMemberVariables

+

Allows to ignore (not diagnose) all the member variables declared with a public access specifier.

+

(Clang-Tidy original name: misc-non-private-member-variables-in-classes)

+ + +#### Redundant Expression {#CT_MSC_RE} +

Detect redundant expressions which are typically errors due to copy-paste.

+

Depending on the operator expressions may be

+
    +
  • redundant,
  • +
  • always true,
  • +
  • always false,
  • +
  • always a constant (zero or one).
  • +
+

Examples:

+
((x+1) | (x+1))             // (x+1) is redundant
+(p->x == p->x)              // always true
+(p->x < p->x)               // always false
+(speed - speed + 1 == 12)   // speed - speed is always zero
+

(Clang-Tidy original name: misc-redundant-expression)

+ + +#### Static Assert {#CT_MSC_SA2} +

cert-dcl03-c redirects here as an alias for this check.

+

Replaces assert() with static_assert() if the condition is evaluatable at compile time.

+

The condition of static_assert() is evaluated at compile time which is safer and more efficient.

+

(Clang-Tidy original name: misc-static-assert)

+ + +#### Throw By Value Catch By Reference {#CT_MSC_TBVCBR} +

cert-err09-cpp redirects here as an alias for this check. cert-err61-cpp redirects here as an alias for this check.

+

Finds violations of the rule “Throw by value, catch by reference” presented for example in “C++ Coding Standards” by H. Sutter and A. Alexandrescu, as well as the CERT C++ Coding Standard rule ERR61-CPP. Catch exceptions by lvalue reference.

+

Exceptions:

+
    +
  • Throwing string literals will not be flagged despite being a pointer. They are not susceptible to slicing and the usage of string literals is idomatic.
  • +
  • Catching character pointers (char, wchar_t, unicode character types) will not be flagged to allow catching sting literals.
  • +
  • Moved named values will not be flagged as not throwing an anonymous temporary. In this case we can be sure that the user knows that the object can’t be accessed outside catch blocks handling the error.
  • +
  • Throwing function parameters will not be flagged as not throwing an anonymous temporary. This allows helper functions for throwing.
  • +
  • Re-throwing caught exception variables will not be flragged as not throwing an anonymous temporary. Although this can usually be done by just writing throw; it happens often enough in real code.
  • +
+
Options
+

CheckThrowTemporaries

+

Triggers detection of violations of the CERT recommendation ERR09-CPP. Throw anonymous temporaries. Default is true.

+

WarnOnLargeObject

+

Also warns for any large, trivial object caught by value. Catching a large object by value is not dangerous but affects the performance negatively. The maximum size of an object allowed to be caught without warning can be set using the MaxSize option. Default is false.

+

MaxSize

+

Determines the maximum size of an object allowed to be caught without warning. Only applicable if WarnOnLargeObject is set to true. If the option is set by the user to std::numeric_limits::max() then it reverts to the default value. Default is the size of size_t.

+

(Clang-Tidy original name: misc-throw-by-value-catch-by-reference)

+ + +#### Unconventional Assign Operator {#CT_MSC_UAO} +

Finds declarations of assign operators with the wrong return and/or argument types and definitions with good return type but wrong return statements.

+
    +
  • The return type must be Class&.
  • +
  • Works with move-assign and assign by value.
  • +
  • Private and deleted operators are ignored.
  • +
  • The operator must always return *this.
  • +
+

(Clang-Tidy original name: misc-unconventional-assign-operator)

+ + +#### Uniqueptr Reset Release {#CT_MSC_URR} +

Find and replace unique_ptr::reset(release()) with std::move().

+

Example:

+
std::unique_ptr<Foo> x, y;
+x.reset(y.release()); -> x = std::move(y);
+

If y is already rvalue, std::move() is not added. x and y can also be std::unique_ptr*.

+

(Clang-Tidy original name: misc-uniqueptr-reset-release)

+ + +#### Unused Alias Decls {#CT_MSC_UAD} +

Finds unused namespace alias declarations.

+
namespace my_namespace {
+class C {};
+}
+namespace unused_alias = ::my_namespace;
+

(Clang-Tidy original name: misc-unused-alias-decls)

+ + +#### Unused Parameters {#CT_MSC_UP} +

Finds unused function parameters. Unused parameters may signify a bug in the code (e.g. when a different parameter is used instead). The suggested fixes either comment parameter name out or remove the parameter completely, if all callers of the function are in the same translation unit and can be updated.

+

The check is similar to the -Wunused-parameter compiler diagnostic and can be used to prepare a codebase to enabling of that diagnostic. By default the check is more permissive (see StrictMode).

+
void a(int i) { /*some code that doesn't use `i`*/ }
+
+// becomes
+
+void a(int  /*i*/) { /*some code that doesn't use `i`*/ }
+
static void staticFunctionA(int i);
+static void staticFunctionA(int i) { /*some code that doesn't use `i`*/ }
+
+// becomes
+
+static void staticFunctionA()
+static void staticFunctionA() { /*some code that doesn't use `i`*/ }
+
Options
+

StrictMode

+

When false (default value), the check will ignore trivially unused parameters, i.e. when the corresponding function has an empty body (and in case of constructors - no constructor initializers). When the function body is empty, an unused parameter is unlikely to be unnoticed by a human reader, and there’s basically no place for a bug to hide.

+

(Clang-Tidy original name: misc-unused-parameters)

+ + +#### Unused Using Decls {#CT_MSC_UUD} +

Finds unused using declarations.

+

Example:

+
namespace n { class C; }
+using n::C;  // Never actually used.
+

(Clang-Tidy original name: misc-unused-using-decls)

+ + +### Modernize + +#### Avoid Bind {#CT_MDR_AB} +

The check finds uses of std::bind and boost::bind and replaces them with lambdas. Lambdas will use value-capture unless reference capture is explicitly requested with std::ref or boost::ref.

+

It supports arbitrary callables including member functions, function objects, and free functions, and all variations thereof. Anything that you can pass to the first argument of bind should be diagnosable. Currently, the only known case where a fix-it is unsupported is when the same placeholder is specified multiple times in the parameter list.

+

Given:

+
int add(int x, int y) { return x + y; }
+

Then:

+
void f() {
+  int x = 2;
+  auto clj = std::bind(add, x, _1);
+}
+

is replaced by:

+
void f() {
+  int x = 2;
+  auto clj = [=](auto && arg1) { return add(x, arg1); };
+}
+

std::bind can be hard to read and can result in larger object files and binaries due to type information that will not be produced by equivalent lambdas.

+
Options
+

PermissiveParameterList

+

If the option is set to true, the check will append auto&&... to the end of every placeholder parameter list. Without this, it is possible for a fix-it to perform an incorrect transformation in the case where the result of the bind is used in the context of a type erased functor such as std::function which allows mismatched arguments. For example:

+
int add(int x, int y) { return x + y; }
+int foo() {
+  std::function<int(int,int)> ignore_args = std::bind(add, 2, 2);
+  return ignore_args(3, 3);
+}
+

is valid code, and returns 4. The actual values passed to ignore_args are simply ignored. Without PermissiveParameterList, this would be transformed into

+
int add(int x, int y) { return x + y; }
+int foo() {
+  std::function<int(int,int)> ignore_args = [] { return add(2, 2); }
+  return ignore_args(3, 3);
+}
+

which will not compile, since the lambda does not contain an operator() that that accepts 2 arguments. With permissive parameter list, it instead generates

+
int add(int x, int y) { return x + y; }
+int foo() {
+  std::function<int(int,int)> ignore_args = [](auto&&...) { return add(2, 2); }
+  return ignore_args(3, 3);
+}
+

which is correct.

+

This check requires using C++14 or higher to run.

+

(Clang-Tidy original name: modernize-avoid-bind)

+ + +#### Avoid C Arrays {#CT_MDR_ACA} +

cppcoreguidelines-avoid-c-arrays redirects here as an alias for this check.

+

hicpp-avoid-c-arrays redirects here as an alias for this check.

+

Finds C-style array types and recommend to use std::array<> / std::vector<>. All types of C arrays are diagnosed.

+

However, fix-it are potentially dangerous in header files and are therefore not emitted right now.

+
int a[] = {1, 2}; // warning: do not declare C-style arrays, use std::array<> instead
+
+int b[1]; // warning: do not declare C-style arrays, use std::array<> instead
+
+void foo() {
+  int c[b[0]]; // warning: do not declare C VLA arrays, use std::vector<> instead
+}
+
+template <typename T, int Size>
+class array {
+  T d[Size]; // warning: do not declare C-style arrays, use std::array<> instead
+
+  int e[1]; // warning: do not declare C-style arrays, use std::array<> instead
+};
+
+array<int[4], 2> d; // warning: do not declare C-style arrays, use std::array<> instead
+
+using k = int[4]; // warning: do not declare C-style arrays, use std::array<> instead
+

However, the extern "C" code is ignored, since it is common to share such headers between C code, and C++ code.

+
// Some header
+extern "C" {
+
+int f[] = {1, 2}; // not diagnosed
+
+int j[1]; // not diagnosed
+
+inline void bar() {
+  {
+    int j[j[0]]; // not diagnosed
+  }
+}
+
+}
+

Similarly, the main() function is ignored. Its second and third parameters can be either char* argv[] or char** argv, but can not be std::array<>.

+

(Clang-Tidy original name: modernize-avoid-c-arrays)

+ + +#### Concat Nested Namespaces {#CT_MDR_CNN} +

Checks for use of nested namespaces such as namespace a { namespace b { ... } } and suggests changing to the more concise syntax introduced in C++17: namespace a::b { ... }. Inline namespaces are not modified.

+

For example:

+
namespace n1 {
+namespace n2 {
+void t();
+}
+}
+
+namespace n3 {
+namespace n4 {
+namespace n5 {
+void t();
+}
+}
+namespace n6 {
+namespace n7 {
+void t();
+}
+}
+}
+

Will be modified to:

+
namespace n1::n2 {
+void t();
+}
+
+namespace n3 {
+namespace n4::n5 {
+void t();
+}
+namespace n6::n7 {
+void t();
+}
+}
+

(Clang-Tidy original name: modernize-concat-nested-namespaces)

+ + +#### Deprecated Headers {#CT_MDR_DH} +

Some headers from C library were deprecated in C++ and are no longer welcome in C++ codebases. Some have no effect in C++. For more details refer to the C++ 14 Standard [depr.c.headers] section.

+

This check replaces C standard library headers with their C++ alternatives and removes redundant ones.

+

Important note: the Standard doesn’t guarantee that the C++ headers declare all the same functions in the global namespace. The check in its current form can break the code that uses library symbols from the global namespace.

+
    +
  • +
  • +
  • +
  • +
  • // deprecated since C++11
  • +
  • +
  • +
  • +
  • +
  • +
  • +
  • +
  • +
  • +
  • +
  • +
  • +
  • +
  • // deprecated since C++11
  • +
  • +
  • // deprecated since C++11
  • +
  • +
  • +
+

If the specified standard is older than C++11 the check will only replace headers deprecated before C++11, otherwise – every header that appeared in the previous list.

+

These headers don’t have effect in C++:

+
    +
  • +
  • +
  • +
+

(Clang-Tidy original name: modernize-deprecated-headers)

+ + +#### Deprecated Ios Base Aliases {#CT_MDR_DIBA} +

Detects usage of the deprecated member types of std::ios_base and replaces those that have a non-deprecated equivalent.

+

Deprecated member type | Replacement
+---|---
+std::ios_base::io_state | std::ios_base::iostate
+std::ios_base::open_mode | std::ios_base::openmode
+std::ios_base::seek_dir | std::ios_base::seekdir
+std::ios_base::streamoff |
+std::ios_base::streampos |

+

(Clang-Tidy original name: modernize-deprecated-ios-base-aliases)

+ + +#### Loop Convert {#CT_MDR_LC} +

This check converts for(...; ...; ...) loops to use the new range-based loops in C++11.

+

Three kinds of loops can be converted:

+
    +
  • Loops over statically allocated arrays.
  • +
  • Loops over containers, using iterators.
  • +
  • Loops over array-like containers, using operator[] and at().
  • +
+
MinConfidence option
+
risky
+

In loops where the container expression is more complex than just a reference to a declared expression (a variable, function, enum, etc.), and some part of it appears elsewhere in the loop, we lower our confidence in the transformation due to the increased risk of changing semantics. Transformations for these loops are marked as risky, and thus will only be converted if the minimum required confidence level is set to risky.

+
int arr[10][20];
+int l = 5;
+
+for (int j = 0; j < 20; ++j)
+  int k = arr[l][j] + l; // using l outside arr[l] is considered risky
+
+for (int i = 0; i < obj.getVector().size(); ++i)
+  obj.foo(10); // using 'obj' is considered risky
+

See Range-based loops evaluate end() only once for an example of an incorrect transformation when the minimum required confidence level is set to risky.

+
reasonable (Default)
+

If a loop calls .end() or .size() after each iteration, the transformation for that loop is marked as reasonable, and thus will be converted if the required confidence level is set to reasonable (default) or lower.

+
// using size() is considered reasonable
+for (int i = 0; i < container.size(); ++i)
+  cout << container[i];
+
safe
+

Any other loops that do not match the above criteria to be marked as risky or reasonable are marked safe, and thus will be converted if the required confidence level is set to safe or lower.

+
int arr[] = {1,2,3};
+
+for (int i = 0; i < 3; ++i)
+  cout << arr[i];
+
Example
+

Original:

+
const int N = 5;
+int arr[] = {1,2,3,4,5};
+vector<int> v;
+v.push_back(1);
+v.push_back(2);
+v.push_back(3);
+
+// safe conversion
+for (int i = 0; i < N; ++i)
+  cout << arr[i];
+
+// reasonable conversion
+for (vector<int>::iterator it = v.begin(); it != v.end(); ++it)
+  cout << *it;
+
+// reasonable conversion
+for (int i = 0; i < v.size(); ++i)
+  cout << v[i];
+

After applying the check with minimum confidence level set to reasonable (default):

+
const int N = 5;
+int arr[] = {1,2,3,4,5};
+vector<int> v;
+v.push_back(1);
+v.push_back(2);
+v.push_back(3);
+
+// safe conversion
+for (auto & elem : arr)
+  cout << elem;
+
+// reasonable conversion
+for (auto & elem : v)
+  cout << elem;
+
+// reasonable conversion
+for (auto & elem : v)
+  cout << elem;
+
Reverse Iterator Support
+

The converter is also capable of transforming iterator loops which use rbegin and rend for looping backwards over a container. Out of the box this will automatically happen in C++20 mode using the ranges library, however the check can be configured to work without C++20 by specifying a function to reverse a range and optionally the header file where that function lives.

+

UseCxx20ReverseRanges

+

When set to true convert loops when in C++20 or later mode using std::ranges::reverse_view. Default value is true.

+

MakeReverseRangeFunction

+

Specify the function used to reverse an iterator pair, the function should accept a class with rbegin and rend methods and return a class with begin and end methods methods that call the rbegin and rend methods respectively. Common examples are ranges::reverse_view and llvm::reverse. Default value is an empty string.

+

MakeReverseRangeHeader

+

Specifies the header file where MakeReverseRangeFunction is declared. For the previous examples this option would be set to range/v3/view/reverse.hpp and llvm/ADT/STLExtras.h respectively. If this is an empty string and MakeReverseRangeFunction is set, the check will proceed on the assumption that the function is already available in the translation unit. This can be wrapped in angle brackets to signify to add the include as a system include. Default value is an empty string.

+

IncludeStyle

+

A string specifying which include-style is used, llvm or google. Default is llvm.

+
Limitations
+

There are certain situations where the tool may erroneously perform transformations that remove information and change semantics. Users of the tool should be aware of the behaviour and limitations of the check outlined by the cases below.

+
Comments inside loop headers
+

Comments inside the original loop header are ignored and deleted when transformed.

+
for (int i = 0; i < N; /* This will be deleted */ ++i) { }
+
Range-based loops evaluate end() only once
+

The C++11 range-based for loop calls .end() only once during the initialization of the loop. If in the original loop .end() is called after each iteration the semantics of the transformed loop may differ.

+
// The following is semantically equivalent to the C++11 range-based for loop,
+// therefore the semantics of the header will not change.
+for (iterator it = container.begin(), e = container.end(); it != e; ++it) { }
+
+// Instead of calling .end() after each iteration, this loop will be
+// transformed to call .end() only once during the initialization of the loop,
+// which may affect semantics.
+for (iterator it = container.begin(); it != container.end(); ++it) { }
+

As explained above, calling member functions of the container in the body of the loop is considered risky. If the called member function modifies the container the semantics of the converted loop will differ due to .end() being called only once.

+
bool flag = false;
+for (vector<T>::iterator it = vec.begin(); it != vec.end(); ++it) {
+  // Add a copy of the first element to the end of the vector.
+  if (!flag) {
+    // This line makes this transformation 'risky'.
+    vec.push_back(*it);
+    flag = true;
+  }
+  cout << *it;
+}
+

The original code above prints out the contents of the container including the newly added element while the converted loop, shown below, will only print the original contents and not the newly added element.

+
bool flag = false;
+for (auto & elem : vec) {
+  // Add a copy of the first element to the end of the vector.
+  if (!flag) {
+    // This line makes this transformation 'risky'
+    vec.push_back(elem);
+    flag = true;
+  }
+  cout << elem;
+}
+

Semantics will also be affected if .end() has side effects. For example, in the case where calls to .end() are logged the semantics will change in the transformed loop if .end() was originally called after each iteration.

+
iterator end() {
+  num_of_end_calls++;
+  return container.end();
+}
+
Overloaded operator->() with side effects
+

Similarly, if operator->() was overloaded to have side effects, such as logging, the semantics will change. If the iterator’s operator->() was used in the original loop it will be replaced with . instead due to the implicit dereference as part of the range-based for loop. Therefore any side effect of the overloaded operator->() will no longer be performed.

+
for (iterator it = c.begin(); it != c.end(); ++it) {
+  it->func(); // Using operator->()
+}
+// Will be transformed to:
+for (auto & elem : c) {
+  elem.func(); // No longer using operator->()
+}
+
Pointers and references to containers
+

While most of the check’s risk analysis is dedicated to determining whether the iterator or container was modified within the loop, it is possible to circumvent the analysis by accessing and modifying the container through a pointer or reference.

+

If the container were directly used instead of using the pointer or reference the following transformation would have only been applied at the risky level since calling a member function of the container is considered risky. The check cannot identify expressions associated with the container that are different than the one used in the loop header, therefore the transformation below ends up being performed at the safe level.

+
vector<int> vec;
+
+vector<int> *ptr = &vec;
+vector<int> &ref = vec;
+
+for (vector<int>::iterator it = vec.begin(), e = vec.end(); it != e; ++it) {
+  if (!flag) {
+    // Accessing and modifying the container is considered risky, but the risk
+    // level is not raised here.
+    ptr->push_back(*it);
+    ref.push_back(*it);
+    flag = true;
+  }
+}
+
OpenMP
+

As range-based for loops are only available since OpenMP 5, this check should not been used on code with a compatibility requirements of OpenMP prior to version 5. It is intentional that this check does not make any attempts to exclude incorrect diagnostics on OpenMP for loops prior to OpenMP 5.

+

To prevent this check to be applied (and to break) OpenMP for loops but still be applied to non-OpenMP for loops the usage of NOLINT (see Suppressing Undesired Diagnostics) on the specific for loops is recommended.

+

(Clang-Tidy original name: modernize-loop-convert)

+ + +#### Make Shared {#CT_MDR_MS} +

This check finds the creation of std::shared_ptr objects by explicitly calling the constructor and a new expression, and replaces it with a call to std::make_shared.

+
auto my_ptr = std::shared_ptr<MyPair>(new MyPair(1, 2));
+
+// becomes
+
+auto my_ptr = std::make_shared<MyPair>(1, 2);
+

This check also finds calls to std::shared_ptr::reset() with a new expression, and replaces it with a call to std::make_shared.

+
my_ptr.reset(new MyPair(1, 2));
+
+// becomes
+
+my_ptr = std::make_shared<MyPair>(1, 2);
+
Options
+

MakeSmartPtrFunction

+

A string specifying the name of make-shared-ptr function. Default is std::make_shared.

+

MakeSmartPtrFunctionHeader

+

A string specifying the corresponding header of make-shared-ptr function. Default is memory.

+

IncludeStyle

+

A string specifying which include-style is used, llvm or google. Default is llvm.

+

IgnoreMacros

+

If set to true, the check will not give warnings inside macros. Default is true.

+

IgnoreDefaultInitialization

+

If set to non-zero, the check does not suggest edits that will transform default initialization into value initialization, as this can cause performance regressions. Default is 1.

+

(Clang-Tidy original name: modernize-make-shared)

+ + +#### Make Unique {#CT_MDR_MU} +

This check finds the creation of std::unique_ptr objects by explicitly calling the constructor and a new expression, and replaces it with a call to std::make_unique, introduced in C++14.

+
auto my_ptr = std::unique_ptr<MyPair>(new MyPair(1, 2));
+
+// becomes
+
+auto my_ptr = std::make_unique<MyPair>(1, 2);
+

This check also finds calls to std::unique_ptr::reset() with a new expression, and replaces it with a call to std::make_unique.

+
my_ptr.reset(new MyPair(1, 2));
+
+// becomes
+
+my_ptr = std::make_unique<MyPair>(1, 2);
+
Options
+

MakeSmartPtrFunction

+

A string specifying the name of make-unique-ptr function. Default is std::make_unique.

+

MakeSmartPtrFunctionHeader

+

A string specifying the corresponding header of make-unique-ptr function. Default is .

+

IncludeStyle

+

A string specifying which include-style is used, llvm or google. Default is llvm.

+

IgnoreMacros

+

If set to true, the check will not give warnings inside macros. Default is true.

+

IgnoreDefaultInitialization

+

If set to non-zero, the check does not suggest edits that will transform default initialization into value initialization, as this can cause performance regressions. Default is 1.

+

(Clang-Tidy original name: modernize-make-unique)

+ + +#### Pass By Value {#CT_MDR_PBV} +

With move semantics added to the language and the standard library updated with move constructors added for many types it is now interesting to take an argument directly by value, instead of by const-reference, and then copy. This check allows the compiler to take care of choosing the best way to construct the copy.

+

The transformation is usually beneficial when the calling code passes an rvalue and assumes the move construction is a cheap operation. This short example illustrates how the construction of the value happens:

+
void foo(std::string s);
+std::string get_str();
+
+void f(const std::string &str) {
+  foo(str);       // lvalue  -> copy construction
+  foo(get_str()); // prvalue -> move construction
+}
+

Note

+

Currently, only constructors are transformed to make use of pass-by-value. Contributions that handle other situations are welcome!

+
Pass-by-value in constructors
+

Replaces the uses of const-references constructor parameters that are copied into class fields. The parameter is then moved with std::move().

+

Since std::move() is a library function declared in it may be necessary to add this include. The check will add the include directive when necessary.

+
 #include <string>
+
+ class Foo {
+ public:
+-  Foo(const std::string &Copied, const std::string &ReadOnly)
+-    : Copied(Copied), ReadOnly(ReadOnly)
++  Foo(std::string Copied, const std::string &ReadOnly)
++    : Copied(std::move(Copied)), ReadOnly(ReadOnly)
+   {}
+
+ private:
+   std::string Copied;
+   const std::string &ReadOnly;
+ };
+
+ std::string get_cwd();
+
+ void f(const std::string &Path) {
+   // The parameter corresponding to 'get_cwd()' is move-constructed. By
+   // using pass-by-value in the Foo constructor we managed to avoid a
+   // copy-construction.
+   Foo foo(get_cwd(), Path);
+ }
+

If the parameter is used more than once no transformation is performed since moved objects have an undefined state. It means the following code will be left untouched:

+
#include <string>
+
+void pass(const std::string &S);
+
+struct Foo {
+  Foo(const std::string &S) : Str(S) {
+    pass(S);
+  }
+
+  std::string Str;
+};
+
Known limitations
+

A situation where the generated code can be wrong is when the object referenced is modified before the assignment in the init-list through a “hidden” reference.

+

Example:

+
 std::string s("foo");
+
+ struct Base {
+   Base() {
+     s = "bar";
+   }
+ };
+
+ struct Derived : Base {
+-  Derived(const std::string &S) : Field(S)
++  Derived(std::string S) : Field(std::move(S))
+   { }
+
+   std::string Field;
+ };
+
+ void f() {
+-  Derived d(s); // d.Field holds "bar"
++  Derived d(s); // d.Field holds "foo"
+ }
+
Note about delayed template parsing
+

When delayed template parsing is enabled, constructors part of templated contexts; templated constructors, constructors in class templates, constructors of inner classes of template classes, etc., are not transformed. Delayed template parsing is enabled by default on Windows as a Microsoft extension: Clang Compiler User’s Manual - Microsoft extensions.

+

Delayed template parsing can be enabled using the -fdelayed-template-parsing flag and disabled using -fno-delayed-template-parsing.

+

Example:

+
  template <typename T> class C {
+    std::string S;
+
+  public:
+=  // using -fdelayed-template-parsing (default on Windows)
+=  C(const std::string &S) : S(S) {}
+
++  // using -fno-delayed-template-parsing (default on non-Windows systems)
++  C(std::string S) : S(std::move(S)) {}
+  };
+

See also

+

For more information about the pass-by-value idiom, read: Want Speed? Pass by Value.

+
Options
+

IncludeStyle

+

A string specifying which include-style is used, llvm or google. Default is llvm.

+

ValuesOnly

+

When true, the check only warns about copied parameters that are already passed by value. Default is false.

+

(Clang-Tidy original name: modernize-pass-by-value)

+ + +#### Raw String Literal {#CT_MDR_RSL} +

This check selectively replaces string literals containing escaped characters with raw string literals.

+

Example:

+
const char *const Quotes{"embedded \"quotes\""};
+const char *const Paragraph{"Line one.\nLine two.\nLine three.\n"};
+const char *const SingleLine{"Single line.\n"};
+const char *const TrailingSpace{"Look here -> \n"};
+const char *const Tab{"One\tTwo\n"};
+const char *const Bell{"Hello!\a  And welcome!"};
+const char *const Path{"C:\\Program Files\\Vendor\\Application.exe"};
+const char *const RegEx{"\\w\\([a-z]\\)"};
+

becomes

+
const char *const Quotes{R"(embedded "quotes")"};
+const char *const Paragraph{"Line one.\nLine two.\nLine three.\n"};
+const char *const SingleLine{"Single line.\n"};
+const char *const TrailingSpace{"Look here -> \n"};
+const char *const Tab{"One\tTwo\n"};
+const char *const Bell{"Hello!\a  And welcome!"};
+const char *const Path{R"(C:\Program Files\Vendor\Application.exe)"};
+const char *const RegEx{R"(\w\([a-z]\))"};
+

The presence of any of the following escapes can cause the string to be converted to a raw string literal: \, ', ", ?, and octal or hexadecimal escapes for printable ASCII characters.

+

A string literal containing only escaped newlines is a common way of writing lines of text output. Introducing physical newlines with raw string literals in this case is likely to impede readability. These string literals are left unchanged.

+

An escaped horizontal tab, form feed, or vertical tab prevents the string literal from being converted. The presence of a horizontal tab, form feed or vertical tab in source code is not visually obvious.

+

(Clang-Tidy original name: modernize-raw-string-literal)

+ + +#### Redundant Void Arg {#CT_MDR_RVA} +

Find and remove redundant void argument lists.

+

Examples: Initial code | Code with applied fixes
+---|---
+int f(void); | int f();
+int (f(void))(void); | int (f())();
+typedef int (f_t(void))(void); | typedef int (f_t())();
+void (C::p)(void); | void (C::p)();
+C::C(void) {} | C::C() {}
+C::~C(void) {} | C::~C() {}

+

(Clang-Tidy original name: modernize-redundant-void-arg)

+ + +#### Replace Auto Ptr {#CT_MDR_RAP} +

This check replaces the uses of the deprecated class std::auto_ptr by std::unique_ptr (introduced in C++11). The transfer of ownership, done by the copy-constructor and the assignment operator, is changed to match std::unique_ptr usage by using explicit calls to std::move().

+

Migration example:

+
-void take_ownership_fn(std::auto_ptr<int> int_ptr);
++void take_ownership_fn(std::unique_ptr<int> int_ptr);
+
+ void f(int x) {
+-  std::auto_ptr<int> a(new int(x));
+-  std::auto_ptr<int> b;
++  std::unique_ptr<int> a(new int(x));
++  std::unique_ptr<int> b;
+
+-  b = a;
+-  take_ownership_fn(b);
++  b = std::move(a);
++  take_ownership_fn(std::move(b));
+ }
+

Since std::move() is a library function declared in it may be necessary to add this include. The check will add the include directive when necessary.

+
Known Limitations
+
    +
  • If headers modification is not activated or if a header is not allowed to be changed this check will produce broken code (compilation error), where the headers’ code will stay unchanged while the code using them will be changed.
  • +
  • Client code that declares a reference to an std::auto_ptr coming from code that can’t be migrated (such as a header coming from a 3rd party library) will produce a compilation error after migration. This is because the type of the reference will be changed to std::unique_ptr but the type returned by the library won’t change, binding a reference to std::unique_ptr from an std::auto_ptr. This pattern doesn’t make much sense and usually std::auto_ptr are stored by value (otherwise what is the point in using them instead of a reference or a pointer?).
  • +
+
 // <3rd-party header...>
+ std::auto_ptr<int> get_value();
+ const std::auto_ptr<int> & get_ref();
+
+ // <calling code (with migration)...>
+-std::auto_ptr<int> a(get_value());
++std::unique_ptr<int> a(get_value()); // ok, unique_ptr constructed from auto_ptr
+
+-const std::auto_ptr<int> & p = get_ptr();
++const std::unique_ptr<int> & p = get_ptr(); // won't compile
+
    +
  • Non-instantiated templates aren’t modified.
  • +
+
template <typename X>
+void f() {
+    std::auto_ptr<X> p;
+}
+
+// only 'f<int>()' (or similar) will trigger the replacement.
+
Options
+

IncludeStyle

+

A string specifying which include-style is used, llvm or google. Default is llvm.

+

(Clang-Tidy original name: modernize-replace-auto-ptr)

+ + +#### Replace Disallow Copy And Assign Macro {#CT_MDR_RDCAAM} +

Finds macro expansions of DISALLOW_COPY_AND_ASSIGN(Type) and replaces them with a deleted copy constructor and a deleted assignment operator.

+

Before the delete keyword was introduced in C++11 it was common practice to declare a copy constructor and an assignment operator as a private members. This effectively makes them unusable to the public API of a class.

+

With the advent of the delete keyword in C++11 we can abandon the private access of the copy constructor and the assignment operator and delete the methods entirely.

+

When running this check on a code like this:

+
class Foo {
+private:
+  DISALLOW_COPY_AND_ASSIGN(Foo);
+};
+

It will be transformed to this:

+
class Foo {
+private:
+  Foo(const Foo &) = delete;
+  const Foo &operator=(const Foo &) = delete;
+};
+
Known Limitations
+
    +
  • Notice that the migration example above leaves the private access specification untouched. You might want to run the check modernize-use-equals-delete to get warnings for deleted functions in private sections.
  • +
+
Options
+

MacroName

+

A string specifying the macro name whose expansion will be replaced. Default is DISALLOW_COPY_AND_ASSIGN.

+

See: https://en.cppreference.com/w/cpp/language/function\#Deleted_functions

+

(Clang-Tidy original name: modernize-replace-disallow-copy-and-assign-macro)

+ + +#### Replace Random Shuffle {#CT_MDR_RRS} +

This check will find occurrences of std::random_shuffle and replace it with std::shuffle. In C++17 std::random_shuffle will no longer be available and thus we need to replace it.

+

Below are two examples of what kind of occurrences will be found and two examples of what it will be replaced with.

+
std::vector<int> v;
+
+// First example
+std::random_shuffle(vec.begin(), vec.end());
+
+// Second example
+std::random_shuffle(vec.begin(), vec.end(), randomFunc);
+

Both of these examples will be replaced with:

+
std::shuffle(vec.begin(), vec.end(), std::mt19937(std::random_device()()));
+

The second example will also receive a warning that randomFunc is no longer supported in the same way as before so if the user wants the same functionality, the user will need to change the implementation of the randomFunc.

+

One thing to be aware of here is that std::random_device is quite expensive to initialize. So if you are using the code in a performance critical place, you probably want to initialize it elsewhere. Another thing is that the seeding quality of the suggested fix is quite poor: std::mt19937 has an internal state of 624 32-bit integers, but is only seeded with a single integer. So if you require higher quality randomness, you should consider seeding better, for example:

+
std::shuffle(v.begin(), v.end(), []() {
+  std::mt19937::result_type seeds[std::mt19937::state_size];
+  std::random_device device;
+  std::uniform_int_distribution<typename std::mt19937::result_type> dist;
+  std::generate(std::begin(seeds), std::end(seeds), [&] { return dist(device); });
+  std::seed_seq seq(std::begin(seeds), std::end(seeds));
+  return std::mt19937(seq);
+}());
+

(Clang-Tidy original name: modernize-replace-random-shuffle)

+ + +#### Return Braced Init List {#CT_MDR_RBIL} +

Replaces explicit calls to the constructor in a return with a braced initializer list. This way the return type is not needlessly duplicated in the function definition and the return statement.

+
Foo bar() {
+  Baz baz;
+  return Foo(baz);
+}
+
+// transforms to:
+
+Foo bar() {
+  Baz baz;
+  return {baz};
+}
+

(Clang-Tidy original name: modernize-return-braced-init-list)

+ + +#### Shrink To Fit {#CT_MDR_STF} +

Replace copy and swap tricks on shrinkable containers with the shrink_to_fit() method call.

+

The shrink_to_fit() method is more readable and more effective than the copy and swap trick to reduce the capacity of a shrinkable container. Note that, the shrink_to_fit() method is only available in C++11 and up.

+

(Clang-Tidy original name: modernize-shrink-to-fit)

+ + +#### Unary Static Assert {#CT_MDR_USA} +

The check diagnoses any static_assert declaration with an empty string literal and provides a fix-it to replace the declaration with a single-argument static_assert declaration.

+

The check is only applicable for C++17 and later code.

+

The following code:

+
void f_textless(int a) {
+  static_assert(sizeof(a) <= 10, "");
+}
+

is replaced by:

+
void f_textless(int a) {
+  static_assert(sizeof(a) <= 10);
+}
+

(Clang-Tidy original name: modernize-unary-static-assert)

+ + +#### Use Auto {#CT_MDR_UA} +

This check is responsible for using the auto type specifier for variable declarations to improve code readability and maintainability. For example:

+
std::vector<int>::iterator I = my_container.begin();
+
+// transforms to:
+
+auto I = my_container.begin();
+

The auto type specifier will only be introduced in situations where the variable type matches the type of the initializer expression. In other words auto should deduce the same type that was originally spelled in the source. However, not every situation should be transformed:

+
int val = 42;
+InfoStruct &I = SomeObject.getInfo();
+
+// Should not become:
+
+auto val = 42;
+auto &I = SomeObject.getInfo();
+

In this example using auto for builtins doesn’t improve readability. In other situations it makes the code less self-documenting impairing readability and maintainability. As a result, auto is used only introduced in specific situations described below.

+
Iterators
+

Iterator type specifiers tend to be long and used frequently, especially in loop constructs. Since the functions generating iterators have a common format, the type specifier can be replaced without obscuring the meaning of code while improving readability and maintainability.

+
for (std::vector<int>::iterator I = my_container.begin(),
+                                E = my_container.end();
+     I != E; ++I) {
+}
+
+// becomes
+
+for (auto I = my_container.begin(), E = my_container.end(); I != E; ++I) {
+}
+

The check will only replace iterator type-specifiers when all of the following conditions are satisfied:

+
    +
  • The iterator is for one of the standard container in std namespace: +
      +
    • array
    • +
    • deque
    • +
    • forward_list
    • +
    • list
    • +
    • vector
    • +
    • map
    • +
    • multimap
    • +
    • set
    • +
    • multiset
    • +
    • unordered_map
    • +
    • unordered_multimap
    • +
    • unordered_set
    • +
    • unordered_multiset
    • +
    • queue
    • +
    • priority_queue
    • +
    • stack
    • +
  • +
  • The iterator is one of the possible iterator types for standard containers: +
      +
    • iterator
    • +
    • reverse_iterator
    • +
    • const_iterator
    • +
    • const_reverse_iterator
    • +
  • +
  • In addition to using iterator types directly, typedefs or other ways of referring to those types are also allowed. However, implementation-specific types for which a type like std::vector::iterator is itself a typedef will not be transformed. Consider the following examples:
  • +
+
// The following direct uses of iterator types will be transformed.
+std::vector<int>::iterator I = MyVec.begin();
+{
+  using namespace std;
+  list<int>::iterator I = MyList.begin();
+}
+
+// The type specifier for J would transform to auto since it's a typedef
+// to a standard iterator type.
+typedef std::map<int, std::string>::const_iterator map_iterator;
+map_iterator J = MyMap.begin();
+
+// The following implementation-specific iterator type for which
+// std::vector<int>::iterator could be a typedef would not be transformed.
+__gnu_cxx::__normal_iterator<int*, std::vector> K = MyVec.begin();
+
    +
  • The initializer for the variable being declared is not a braced initializer list. Otherwise, use of auto would cause the type of the variable to be deduced as std::initializer_list.
  • +
+
New expressions
+

Frequently, when a pointer is declared and initialized with new, the pointee type is written twice: in the declaration type and in the new expression. In this cases, the declaration type can be replaced with auto improving readability and maintainability.

+
TypeName *my_pointer = new TypeName(my_param);
+
+// becomes
+
+auto *my_pointer = new TypeName(my_param);
+

The check will also replace the declaration type in multiple declarations, if the following conditions are satisfied:

+
    +
  • All declared variables have the same type (i.e. all of them are pointers to the same type).
  • +
  • All declared variables are initialized with a new expression.
  • +
  • The types of all the new expressions are the same than the pointee of the declaration type.
  • +
+
TypeName *my_first_pointer = new TypeName, *my_second_pointer = new TypeName;
+
+// becomes
+
+auto *my_first_pointer = new TypeName, *my_second_pointer = new TypeName;
+
Cast expressions
+

Frequently, when a variable is declared and initialized with a cast, the variable type is written twice: in the declaration type and in the cast expression. In this cases, the declaration type can be replaced with auto improving readability and maintainability.

+
TypeName *my_pointer = static_cast<TypeName>(my_param);
+
+// becomes
+
+auto *my_pointer = static_cast<TypeName>(my_param);
+

The check handles static_cast, dynamic_cast, const_cast, reinterpret_cast, functional casts, C-style casts and function templates that behave as casts, such as llvm::dyn_cast, boost::lexical_cast and gsl::narrow_cast. Calls to function templates are considered to behave as casts if the first template argument is explicit and is a type, and the function returns that type, or a pointer or reference to it.

+
Known Limitations
+
    +
  • If the initializer is an explicit conversion constructor, the check will not replace the type specifier even though it would be safe to do so.
  • +
  • User-defined iterators are not handled at this time.
  • +
+
Options
+

MinTypeNameLength

+

If the option is set to non-zero (default 5), the check will ignore type names having a length less than the option value. The option affects expressions only, not iterators. Spaces between multi-lexeme type names (long int) are considered as one. If the RemoveStars option (see below) is set to true, then *s in the type are also counted as a part of the type name.

+
// MinTypeNameLength = 0, RemoveStars=0
+
+int a = static_cast<int>(foo());            // ---> auto a = ...
+// length(bool *) = 4
+bool *b = new bool;                         // ---> auto *b = ...
+unsigned c = static_cast<unsigned>(foo());  // ---> auto c = ...
+
+// MinTypeNameLength = 5, RemoveStars=0
+
+int a = static_cast<int>(foo());                 // ---> int  a = ...
+bool b = static_cast<bool>(foo());               // ---> bool b = ...
+bool *pb = static_cast<bool*>(foo());            // ---> bool *pb = ...
+unsigned c = static_cast<unsigned>(foo());       // ---> auto c = ...
+// length(long <on-or-more-spaces> int) = 8
+long int d = static_cast<long int>(foo());       // ---> auto d = ...
+
+// MinTypeNameLength = 5, RemoveStars=1
+
+int a = static_cast<int>(foo());                 // ---> int  a = ...
+// length(int * * ) = 5
+int **pa = static_cast<int**>(foo());            // ---> auto pa = ...
+bool b = static_cast<bool>(foo());               // ---> bool b = ...
+bool *pb = static_cast<bool*>(foo());            // ---> auto pb = ...
+unsigned c = static_cast<unsigned>(foo());       // ---> auto c = ...
+long int d = static_cast<long int>(foo());       // ---> auto d = ...
+

RemoveStars

+

If the option is set to true (default is false), the check will remove stars from the non-typedef pointer types when replacing type names with auto. Otherwise, the check will leave stars. For example:

+
TypeName *my_first_pointer = new TypeName, *my_second_pointer = new TypeName;
+
+// RemoveStars = 0
+
+auto *my_first_pointer = new TypeName, *my_second_pointer = new TypeName;
+
+// RemoveStars = 1
+
+auto my_first_pointer = new TypeName, my_second_pointer = new TypeName;
+

(Clang-Tidy original name: modernize-use-auto)

+ + +#### Use Bool Literals {#CT_MDR_UBL} +

Finds integer literals which are cast to bool.

+
bool p = 1;
+bool f = static_cast<bool>(1);
+std::ios_base::sync_with_stdio(0);
+bool x = p ? 1 : 0;
+
+// transforms to
+
+bool p = true;
+bool f = true;
+std::ios_base::sync_with_stdio(false);
+bool x = p ? true : false;
+
Options
+

IgnoreMacros

+

If set to true, the check will not give warnings inside macros. Default is true.

+

(Clang-Tidy original name: modernize-use-bool-literals)

+ + +#### Use Default Member Init {#CT_MDR_UDMI} +

This check converts a default constructor’s member initializers into the new default member initializers in C++11. Other member initializers that match the default member initializer are removed. This can reduce repeated code or allow use of ‘= default’.

+
struct A {
+  A() : i(5), j(10.0) {}
+  A(int i) : i(i), j(10.0) {}
+  int i;
+  double j;
+};
+
+// becomes
+
+struct A {
+  A() {}
+  A(int i) : i(i) {}
+  int i{5};
+  double j{10.0};
+};
+

Note

+

Only converts member initializers for built-in types, enums, and pointers. The readability-redundant-member-init check will remove redundant member initializers for classes.

+
Options
+

UseAssignment

+

If this option is set to true (default is false), the check will initialise members with an assignment. For example:

+
struct A {
+  A() {}
+  A(int i) : i(i) {}
+  int i = 5;
+  double j = 10.0;
+};
+

IgnoreMacros

+

If this option is set to true (default is true), the check will not warn about members declared inside macros.

+

(Clang-Tidy original name: modernize-use-default-member-init)

+ + +#### Use Emplace {#CT_MDR_UE} +

The check flags insertions to an STL-style container done by calling the push_back method with an explicitly-constructed temporary of the container element type. In this case, the corresponding emplace_back method results in less verbose and potentially more efficient code. Right now the check doesn’t support push_front and insert. It also doesn’t support insert functions for associative containers because replacing insert with emplace may result in speed regression, but it might get support with some addition flag in the future.

+

By default only std::vector, std::deque, std::list are considered. This list can be modified using the ContainersWithPushBack option.

+

Before:

+
std::vector<MyClass> v;
+v.push_back(MyClass(21, 37));
+
+std::vector<std::pair<int, int>> w;
+
+w.push_back(std::pair<int, int>(21, 37));
+w.push_back(std::make_pair(21L, 37L));
+

After:

+
std::vector<MyClass> v;
+v.emplace_back(21, 37);
+
+std::vector<std::pair<int, int>> w;
+w.emplace_back(21, 37);
+w.emplace_back(21L, 37L);
+

By default, the check is able to remove unnecessary std::make_pair and std::make_tuple calls from push_back calls on containers of std::pair and std::tuple. Custom tuple-like types can be modified by the TupleTypes option; custom make functions can be modified by the TupleMakeFunctions option.

+

The other situation is when we pass arguments that will be converted to a type inside a container.

+

Before:

+
std::vector<boost::optional<std::string> > v;
+v.push_back("abc");
+

After:

+
std::vector<boost::optional<std::string> > v;
+v.emplace_back("abc");
+

In some cases the transformation would be valid, but the code wouldn’t be exception safe. In this case the calls of push_back won’t be replaced.

+
std::vector<std::unique_ptr<int>> v;
+v.push_back(std::unique_ptr<int>(new int(0)));
+auto *ptr = new int(1);
+v.push_back(std::unique_ptr<int>(ptr));
+

This is because replacing it with emplace_back could cause a leak of this pointer if emplace_back would throw exception before emplacement (e.g. not enough memory to add a new element).

+

For more info read item 42 - “Consider emplacement instead of insertion.” of Scott Meyers “Effective Modern C++”.

+

The default smart pointers that are considered are std::unique_ptr, std::shared_ptr, std::auto_ptr. To specify other smart pointers or other classes use the SmartPointers option.

+

Check also doesn’t fire if any argument of the constructor call would be:

+
    +
  • a bit-field (bit-fields can’t bind to rvalue/universal reference)
  • +
  • a new expression (to avoid leak)
  • +
  • if the argument would be converted via derived-to-base cast.
  • +
+

This check requires C++11 or higher to run.

+
Options
+

ContainersWithPushBack

+

Semicolon-separated list of class names of custom containers that support push_back.

+

IgnoreImplicitConstructors

+

When true, the check will ignore implicitly constructed arguments of push_back, e.g.

+
std::vector<std::string> v;
+v.push_back("a"); // Ignored when IgnoreImplicitConstructors is `true`.
+

Default is false.

+

SmartPointers

+

Semicolon-separated list of class names of custom smart pointers.

+

TupleTypes

+

Semicolon-separated list of std::tuple-like class names.

+

TupleMakeFunctions

+

Semicolon-separated list of std::make_tuple-like function names. Those function calls will be removed from push_back calls and turned into emplace_back.

+
Example
+
std::vector<MyTuple<int, bool, char>> x;
+x.push_back(MakeMyTuple(1, false, 'x'));
+

transforms to:

+
std::vector<MyTuple<int, bool, char>> x;
+x.emplace_back(1, false, 'x');
+

when TupleTypes is set to MyTuple and TupleMakeFunctions is set to MakeMyTuple.

+

(Clang-Tidy original name: modernize-use-emplace)

+ + +#### Use Equals Default {#CT_MDR_UED} +

This check replaces default bodies of special member functions with = default;. The explicitly defaulted function declarations enable more opportunities in optimization, because the compiler might treat explicitly defaulted functions as trivial.

+
struct A {
+  A() {}
+  ~A();
+};
+A::~A() {}
+
+// becomes
+
+struct A {
+  A() = default;
+  ~A();
+};
+A::~A() = default;
+

Note

+

Move-constructor and move-assignment operator are not supported yet.

+
Options
+

IgnoreMacros

+

If set to true, the check will not give warnings inside macros. Default is true.

+

(Clang-Tidy original name: modernize-use-equals-default)

+ + +#### Use Equals Delete {#CT_MDR_UED2} +

This check marks unimplemented private special member functions with = delete. To avoid false-positives, this check only applies in a translation unit that has all other member functions implemented.

+
struct A {
+private:
+  A(const A&);
+  A& operator=(const A&);
+};
+
+// becomes
+
+struct A {
+private:
+  A(const A&) = delete;
+  A& operator=(const A&) = delete;
+};
+

IgnoreMacros

+

If this option is set to true (default is true), the check will not warn about functions declared inside macros.

+

(Clang-Tidy original name: modernize-use-equals-delete)

+ + +#### Use Nodiscard {#CT_MDR_UN} +

Adds [[nodiscard]] attributes (introduced in C++17) to member functions in order to highlight at compile time which return values should not be ignored.

+

Member functions need to satisfy the following conditions to be considered by this check:

+
    +
  • no [[nodiscard]], [[noreturn]], attribute((warn_unused_result)), [[clang::warn_unused_result]] nor [[gcc::warn_unused_result]] attribute,
  • +
  • non-void return type,
  • +
  • non-template return types,
  • +
  • const member function,
  • +
  • non-variadic functions,
  • +
  • no non-const reference parameters,
  • +
  • no pointer parameters,
  • +
  • no template parameters,
  • +
  • no template function parameters,
  • +
  • not be a member of a class with mutable member variables,
  • +
  • no Lambdas,
  • +
  • no conversion functions.
  • +
+

Such functions have no means of altering any state or passing values other than via the return type. Unless the member functions are altering state via some external call (e.g. I/O).

+
Example
+
bool empty() const;
+bool empty(int i) const;
+

transforms to:

+
[[nodiscard] bool empty() const;
+[[nodiscard] bool empty(int i) const;
+
Options
+

ReplacementString

+

Specifies a macro to use instead of [[nodiscard]]. This is useful when maintaining source code that needs to compile with a pre-C++17 compiler.

+
Example
+
bool empty() const;
+bool empty(int i) const;
+

transforms to:

+
NO_DISCARD bool empty() const;
+NO_DISCARD bool empty(int i) const;
+

if the ReplacementString option is set to NO_DISCARD.

+

Note

+

If the ReplacementString is not a C++ attribute, but instead a macro, then that macro must be defined in scope or the fix-it will not be applied.

+

Note

+

For alternative attribute syntax options to mark functions as [[nodiscard]] in non-c++17 source code. See https://clang.llvm.org/docs/AttributeReference.html\#nodiscard-warn-unused-result

+

(Clang-Tidy original name: modernize-use-nodiscard)

+ + +#### Use Noexcept {#CT_MDR_UN2} +

This check replaces deprecated dynamic exception specifications with the appropriate noexcept specification (introduced in C++11). By default this check will replace throw() with noexcept, and throw([,...]) or throw(...) with noexcept(false).

+
Example
+
void foo() throw();
+void bar() throw(int) {}
+

transforms to:

+
void foo() noexcept;
+void bar() noexcept(false) {}
+
Options
+

ReplacementString

+

Users can use ReplacementString to specify a macro to use instead of noexcept. This is useful when maintaining source code that uses custom exception specification marking other than noexcept. Fix-it hints will only be generated for non-throwing specifications.

+
Example
+
void bar() throw(int);
+void foo() throw();
+

transforms to:

+
void bar() throw(int);  // No fix-it generated.
+void foo() NOEXCEPT;
+

if the ReplacementString option is set to NOEXCEPT.

+

UseNoexceptFalse

+

Enabled by default, disabling will generate fix-it hints that remove throwing dynamic exception specs, e.g., throw(), completely without providing a replacement text, except for destructors and delete operators that are noexcept(true) by default.

+
Example
+
void foo() throw(int) {}
+
+struct bar {
+  void foobar() throw(int);
+  void operator delete(void *ptr) throw(int);
+  void operator delete[](void *ptr) throw(int);
+  ~bar() throw(int);
+}
+

transforms to:

+
void foo() {}
+
+struct bar {
+  void foobar();
+  void operator delete(void *ptr) noexcept(false);
+  void operator delete[](void *ptr) noexcept(false);
+  ~bar() noexcept(false);
+}
+

if the UseNoexceptFalse option is set to false.

+

(Clang-Tidy original name: modernize-use-noexcept)

+ + +#### Use Nullptr {#CT_MDR_UN3} +

The check converts the usage of null pointer constants (eg. NULL, 0) to use the new C++11 nullptr keyword.

+
Example
+
void assignment() {
+  char *a = NULL;
+  char *b = 0;
+  char c = 0;
+}
+
+int *ret_ptr() {
+  return 0;
+}
+

transforms to:

+
void assignment() {
+  char *a = nullptr;
+  char *b = nullptr;
+  char c = 0;
+}
+
+int *ret_ptr() {
+  return nullptr;
+}
+
Options
+

NullMacros

+

Comma-separated list of macro names that will be transformed along with NULL. By default this check will only replace the NULL macro and will skip any similar user-defined macros.

+
Example
+
#define MY_NULL (void*)0
+void assignment() {
+  void *p = MY_NULL;
+}
+

transforms to:

+
#define MY_NULL NULL
+void assignment() {
+  int *p = nullptr;
+}
+

if the NullMacros option is set to MY_NULL.

+

(Clang-Tidy original name: modernize-use-nullptr)

+ + +#### Use Override {#CT_MDR_UO} +

Adds override (introduced in C++11) to overridden virtual functions and removes virtual from those functions as it is not required.

+

virtual on non base class implementations was used to help indicate to the user that a function was virtual. C++ compilers did not use the presence of this to signify an overridden function.

+

In C++ 11 override and final keywords were introduced to allow overridden functions to be marked appropriately. Their presence allows compilers to verify that an overridden function correctly overrides a base class implementation.

+

This can be useful as compilers can generate a compile time error when:

+
    +
  • The base class implementation function signature changes.
  • +
  • The user has not created the override with the correct signature.
  • +
+
Options
+

IgnoreDestructors

+

If set to true, this check will not diagnose destructors. Default is false.

+

AllowOverrideAndFinal

+

If set to true, this check will not diagnose override as redundant with final. This is useful when code will be compiled by a compiler with warning/error checking flags requiring override explicitly on overridden members, such as gcc -Wsuggest-override/gcc -Werror=suggest-override. Default is false.

+

OverrideSpelling

+

Specifies a macro to use instead of override. This is useful when maintaining source code that also needs to compile with a pre-C++11 compiler.

+

FinalSpelling

+

Specifies a macro to use instead of final. This is useful when maintaining source code that also needs to compile with a pre-C++11 compiler.

+

Note

+

For more information on the use of override see https://en.cppreference.com/w/cpp/language/override

+

(Clang-Tidy original name: modernize-use-override)

+ + +#### Use Trailing Return Type {#CT_MDR_UTRT} +

Rewrites function signatures to use a trailing return type (introduced in C++11). This transformation is purely stylistic. The return type before the function name is replaced by auto and inserted after the function parameter list (and qualifiers).

+
Example
+
int f1();
+inline int f2(int arg) noexcept;
+virtual float f3() const && = delete;
+

transforms to:

+
auto f1() -> int;
+inline auto f2(int arg) -> int noexcept;
+virtual auto f3() const && -> float = delete;
+
Known Limitations
+

The following categories of return types cannot be rewritten currently:

+
    +
  • function pointers
  • +
  • member function pointers
  • +
  • member pointers
  • +
+

Unqualified names in the return type might erroneously refer to different entities after the rewrite. Preventing such errors requires a full lookup of all unqualified names present in the return type in the scope of the trailing return type location. This location includes e.g. function parameter names and members of the enclosing class (including all inherited classes). Such a lookup is currently not implemented.

+

Given the following piece of code

+
struct S { long long value; };
+S f(unsigned S) { return {S * 2}; }
+class CC {
+  int S;
+  struct S m();
+};
+S CC::m() { return {0}; }
+

a careless rewrite would produce the following output:

+
struct S { long long value; };
+auto f(unsigned S) -> S { return {S * 2}; } // error
+class CC {
+  int S;
+  auto m() -> struct S;
+};
+auto CC::m() -> S { return {0}; } // error
+

This code fails to compile because the S in the context of f refers to the equally named function parameter. Similarly, the S in the context of m refers to the equally named class member. The check can currently only detect and avoid a clash with a function parameter name.

+

(Clang-Tidy original name: modernize-use-trailing-return-type)

+ + +#### Use Transparent Functors {#CT_MDR_UTF} +

Prefer transparent functors to non-transparent ones. When using transparent functors, the type does not need to be repeated. The code is easier to read, maintain and less prone to errors. It is not possible to introduce unwanted conversions.

+
// Non-transparent functor
+std::map<int, std::string, std::greater<int>> s;
+
+// Transparent functor.
+std::map<int, std::string, std::greater<>> s;
+
+// Non-transparent functor
+using MyFunctor = std::less<MyType>;
+

It is not always a safe transformation though. The following case will be untouched to preserve the semantics.

+
// Non-transparent functor
+std::map<const char *, std::string, std::greater<std::string>> s;
+
Options
+

SafeMode

+

If the option is set to true, the check will not diagnose cases where using a transparent functor cannot be guaranteed to produce identical results as the original code. The default value for this option is false.

+

This check requires using C++14 or higher to run.

+

(Clang-Tidy original name: modernize-use-transparent-functors)

+ + +#### Use Uncaught Exceptions {#CT_MDR_UUE} +

This check will warn on calls to std::uncaught_exception and replace them with calls to std::uncaught_exceptions, since std::uncaught_exception was deprecated in C++17.

+

Below are a few examples of what kind of occurrences will be found and what they will be replaced with.

+
#define MACRO1 std::uncaught_exception
+#define MACRO2 std::uncaught_exception
+
+int uncaught_exception() {
+  return 0;
+}
+
+int main() {
+  int res;
+
+  res = uncaught_exception();
+  // No warning, since it is not the deprecated function from namespace std
+
+  res = MACRO2();
+  // Warning, but will not be replaced
+
+  res = std::uncaught_exception();
+  // Warning and replaced
+
+  using std::uncaught_exception;
+  // Warning and replaced
+
+  res = uncaught_exception();
+  // Warning and replaced
+}
+

After applying the fixes the code will look like the following:

+
#define MACRO1 std::uncaught_exception
+#define MACRO2 std::uncaught_exception
+
+int uncaught_exception() {
+  return 0;
+}
+
+int main() {
+  int res;
+
+  res = uncaught_exception();
+
+  res = MACRO2();
+
+  res = std::uncaught_exceptions();
+
+  using std::uncaught_exceptions;
+
+  res = uncaught_exceptions();
+}
+

(Clang-Tidy original name: modernize-use-uncaught-exceptions)

+ + +#### Use Using {#CT_MDR_UU} +

The check converts the usage of typedef with using keyword.

+

Before:

+
typedef int variable;
+
+class Class{};
+typedef void (Class::* MyPtrType)() const;
+
+typedef struct { int a; } R_t, *R_p;
+

After:

+
using variable = int;
+
+class Class{};
+using MyPtrType = void (Class::*)() const;
+
+using R_t = struct { int a; };
+using R_p = R_t*;
+

This check requires using C++11 or higher to run.

+
Options
+

IgnoreMacros

+

If set to true, the check will not give warnings inside macros. Default is true.

+

(Clang-Tidy original name: modernize-use-using)

+ + +### Objective-C + +#### Avoid Nserror Init {#CT_OBC_ANI} +

Finds improper initialization of NSError objects.

+

According to Apple developer document, we should always use factory method errorWithDomain:code:userInfo: to create new NSError objects instead of [NSError alloc] init]. Otherwise it will lead to a warning message during runtime.

+

The corresponding information about NSError creation: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ErrorHandlingCocoa/CreateCustomizeNSError/CreateCustomizeNSError.html

+

(Clang-Tidy original name: objc-avoid-nserror-init)

+ + +#### Dealloc In Category {#CT_OBC_DIC} +

Finds implementations of -dealloc in Objective-C categories. The category implementation will override any -dealloc in the class implementation, potentially causing issues.

+

Classes implement -dealloc to perform important actions to deallocate an object. If a category on the class implements -dealloc, it will override the class’s implementation and unexpected deallocation behavior may occur.

+

(Clang-Tidy original name: objc-dealloc-in-category)

+ + +#### Forbidden Subclassing {#CT_OBC_FS} +

Finds Objective-C classes which are subclasses of classes which are not designed to be subclassed.

+

By default, includes a list of Objective-C classes which are publicly documented as not supporting subclassing.

+

Note

+

Instead of using this check, for code under your control, you should add attribute((objc_subclassing_restricted)) before your @interface declarations to ensure the compiler prevents others from subclassing your Objective-C classes. See https://clang.llvm.org/docs/AttributeReference.html\#objc-subclassing-restricted

+
Options
+

ForbiddenSuperClassNames

+

Semicolon-separated list of names of Objective-C classes which do not support subclassing.

+

Defaults to ABNewPersonViewController;ABPeoplePickerNavigationController;ABPersonViewController;ABUnknownPersonViewController;NSHashTable;NSMapTable;NSPointerArray;NSPointerFunctions;NSTimer;UIActionSheet;UIAlertView;UIImagePickerController;UITextInputMode;UIWebView.

+

(Clang-Tidy original name: objc-forbidden-subclassing)

+ + +#### Missing Hash {#CT_OBC_MH} +

Finds Objective-C implementations that implement -isEqual: without also appropriately implementing -hash.

+

Apple documentation highlights that objects that are equal must have the same hash value: https://developer.apple.com/documentation/objectivec/1418956-nsobject/1418795-isequal?language=objc

+

Note that the check only verifies the presence of -hash in scenarios where its omission could result in unexpected behavior. The verification of the implementation of -hash is the responsibility of the developer, e.g., through the addition of unit tests to verify the implementation.

+

(Clang-Tidy original name: objc-missing-hash)

+ + +#### Nsinvocation Argument Lifetime {#CT_OBC_NAL} +

Finds calls to NSInvocation methods under ARC that don’t have proper argument object lifetimes. When passing Objective-C objects as parameters to the NSInvocation methods getArgument:atIndex: and getReturnValue:, the values are copied by value into the argument pointer, which leads to to incorrect releasing behavior if the object pointers are not declared __unsafe_unretained.

+

For code:

+
id arg;
+[invocation getArgument:&arg atIndex:2];
+
+__strong id returnValue;
+[invocation getReturnValue:&returnValue];
+

The fix will be:

+
__unsafe_unretained id arg;
+[invocation getArgument:&arg atIndex:2];
+
+__unsafe_unretained id returnValue;
+[invocation getReturnValue:&returnValue];
+

The check will warn on being passed instance variable references that have lifetimes other than __unsafe_unretained, but does not propose a fix:

+
// "id _returnValue" is declaration of instance variable of class.
+[invocation getReturnValue:&self->_returnValue];
+

(Clang-Tidy original name: objc-nsinvocation-argument-lifetime)

+ + +#### Property Declaration {#CT_OBC_PD} +

Finds property declarations in Objective-C files that do not follow the pattern of property names in Apple’s programming guide. The property name should be in the format of Lower Camel Case.

+

For code:

+
@property(nonatomic, assign) int LowerCamelCase;
+

The fix will be:

+
@property(nonatomic, assign) int lowerCamelCase;
+

The check will only fix ‘CamelCase’ to ‘camelCase’. In some other cases we will only provide warning messages since the property name could be complicated. Users will need to come up with a proper name by their own.

+

This check also accepts special acronyms as prefixes or suffixes. Such prefixes or suffixes will suppress the Lower Camel Case check according to the guide: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingBasics.html\#//apple_ref/doc/uid/20001281-1002931-BBCFHEAB

+

For a full list of well-known acronyms: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/APIAbbreviations.html\#//apple_ref/doc/uid/20001285-BCIHCGAE

+

The corresponding style rule: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingIvarsAndTypes.html\#//apple_ref/doc/uid/20001284-1001757

+

The check will also accept property declared in category with a prefix of lowercase letters followed by a ‘_’ to avoid naming conflict. For example:

+
@property(nonatomic, assign) int abc_lowerCamelCase;
+

The corresponding style rule: https://developer.apple.com/library/content/qa/qa1908/_index.html

+

(Clang-Tidy original name: objc-property-declaration)

+ + +#### Super Self {#CT_OBC_SS} +

Finds invocations of -self on super instances in initializers of subclasses of NSObject and recommends calling a superclass initializer instead.

+

Invoking -self on super instances in initializers is a common programmer error when the programmer’s original intent is to call a superclass initializer. Failing to call a superclass initializer breaks initializer chaining and can result in invalid object initialization.

+

(Clang-Tidy original name: objc-super-self)

+ + +### OpenMP + +#### Exception Escape {#CT_OMP_EE} +

Analyzes OpenMP Structured Blocks and checks that no exception escapes out of the Structured Block it was thrown in.

+

As per the OpenMP specification, a structured block is an executable statement, possibly compound, with a single entry at the top and a single exit at the bottom. Which means, throw may not be used to to ‘exit’ out of the structured block. If an exception is not caught in the same structured block it was thrown in, the behaviour is undefined.

+

FIXME: this check does not model SEH, setjmp/longjmp.

+

WARNING! This check may be expensive on large source files.

+
Options
+

IgnoredExceptions

+

Comma-separated list containing type names which are not counted as thrown exceptions in the check. Default value is an empty string.

+

(Clang-Tidy original name: openmp-exception-escape)

+ + +#### Use Default None {#CT_OMP_UDN} +

Finds OpenMP directives that are allowed to contain a default clause, but either don’t specify it or the clause is specified but with the kind other than none, and suggests to use the default(none) clause.

+

Using default(none) clause forces developers to explicitly specify data sharing attributes for the variables referenced in the construct, thus making it obvious which variables are referenced, and what is their data sharing attribute, thus increasing readability and possibly making errors easier to spot.

+
Example
+
// ``for`` directive can not have ``default`` clause, no diagnostics.
+void n0(const int a) {
+#pragma omp for
+  for (int b = 0; b < a; b++)
+    ;
+}
+
+// ``parallel`` directive.
+
+// ``parallel`` directive can have ``default`` clause, but said clause is not
+// specified, diagnosed.
+void p0_0() {
+#pragma omp parallel
+  ;
+  // WARNING: OpenMP directive ``parallel`` does not specify ``default``
+  //          clause. Consider specifying ``default(none)`` clause.
+}
+
+// ``parallel`` directive can have ``default`` clause, and said clause is
+// specified, with ``none`` kind, all good.
+void p0_1() {
+#pragma omp parallel default(none)
+  ;
+}
+
+// ``parallel`` directive can have ``default`` clause, and said clause is
+// specified, but with ``shared`` kind, which is not ``none``, diagnose.
+void p0_2() {
+#pragma omp parallel default(shared)
+  ;
+  // WARNING: OpenMP directive ``parallel`` specifies ``default(shared)``
+  //          clause. Consider using ``default(none)`` clause instead.
+}
+
+// ``parallel`` directive can have ``default`` clause, and said clause is
+// specified, but with ``firstprivate`` kind, which is not ``none``, diagnose.
+void p0_3() {
+#pragma omp parallel default(firstprivate)
+  ;
+  // WARNING: OpenMP directive ``parallel`` specifies ``default(firstprivate)``
+  //          clause. Consider using ``default(none)`` clause instead.
+}
+

(Clang-Tidy original name: openmp-use-default-none)

+ + +### Performance + +#### Faster String Find {#CT_PRF_FSF} +

Optimize calls to std::string::find() and friends when the needle passed is a single character string literal. The character literal overload is more efficient.

+

Examples:

+
str.find("A");
+
+// becomes
+
+str.find('A');
+
Options
+

StringLikeClasses

+

Semicolon-separated list of names of string-like classes. By default only ::std::basic_string and ::std::basic_string_view are considered. The check will only consider member functions named find, rfind, find_first_of, find_first_not_of, find_last_of, or find_last_not_of within these classes.

+

(Clang-Tidy original name: performance-faster-string-find)

+ + +#### For Range Copy {#CT_PRF_FRC} +

Finds C++11 for ranges where the loop variable is copied in each iteration but it would suffice to obtain it by const reference.

+

The check is only applied to loop variables of types that are expensive to copy which means they are not trivially copyable or have a non-trivial copy constructor or destructor.

+

To ensure that it is safe to replace the copy with a const reference the following heuristic is employed:

+
    +
  1. The loop variable is const qualified.
  2. +
  3. The loop variable is not const, but only const methods or operators are invoked on it, or it is used as const reference or value argument in constructors or function calls.
  4. +
+
Options
+

WarnOnAllAutoCopies

+

When true, warns on any use of auto as the type of the range-based for loop variable. Default is false.

+

AllowedTypes

+

A semicolon-separated list of names of types allowed to be copied in each iteration. Regular expressions are accepted, e.g. [Rr]ef(erence)?$ matches every type with suffix Ref, ref, Reference and reference. The default is empty.

+

(Clang-Tidy original name: performance-for-range-copy)

+ + +#### Implicit Conversion In Loop {#CT_PRF_ICIL} +

This warning appears in a range-based loop with a loop variable of const ref type where the type of the variable does not match the one returned by the iterator. This means that an implicit conversion happens, which can for example result in expensive deep copies.

+

Example:

+
map<int, vector<string>> my_map;
+for (const pair<int, vector<string>>& p : my_map) {}
+// The iterator type is in fact pair<const int, vector<string>>, which means
+// that the compiler added a conversion, resulting in a copy of the vectors.
+

The easiest solution is usually to use const auto& instead of writing the type manually.

+

(Clang-Tidy original name: performance-implicit-conversion-in-loop)

+ + +#### Inefficient Algorithm {#CT_PRF_IA} +

Warns on inefficient use of STL algorithms on associative containers.

+

Associative containers implements some of the algorithms as methods which should be preferred to the algorithms in the algorithm header. The methods can take advantage of the order of the elements.

+
std::set<int> s;
+auto it = std::find(s.begin(), s.end(), 43);
+
+// becomes
+
+auto it = s.find(43);
+
std::set<int> s;
+auto c = std::count(s.begin(), s.end(), 43);
+
+// becomes
+
+auto c = s.count(43);
+

(Clang-Tidy original name: performance-inefficient-algorithm)

+ + +#### Inefficient String Concatenation {#CT_PRF_ISC} +

This check warns about the performance overhead arising from concatenating strings using the operator+, for instance:

+
std::string a("Foo"), b("Bar");
+a = a + b;
+

Instead of this structure you should use operator+= or std::string’s (std::basic_string) class member function append(). For instance:

+
std::string a("Foo"), b("Baz");
+for (int i = 0; i < 20000; ++i) {
+    a = a + "Bar" + b;
+}
+

Could be rewritten in a greatly more efficient way like:

+
std::string a("Foo"), b("Baz");
+for (int i = 0; i < 20000; ++i) {
+    a.append("Bar").append(b);
+}
+

And this can be rewritten too:

+
void f(const std::string&) {}
+std::string a("Foo"), b("Baz");
+void g() {
+    f(a + "Bar" + b);
+}
+

In a slightly more efficient way like:

+
void f(const std::string&) {}
+std::string a("Foo"), b("Baz");
+void g() {
+    f(std::string(a).append("Bar").append(b));
+}
+
Options
+

StrictMode

+

When false, the check will only check the string usage in while, for and for-range statements. Default is false.

+

(Clang-Tidy original name: performance-inefficient-string-concatenation)

+ + +#### Inefficient Vector Operation {#CT_PRF_IVO} +

Finds possible inefficient std::vector operations (e.g. push_back, emplace_back) that may cause unnecessary memory reallocations.

+

It can also find calls that add element to protobuf repeated field in a loop without calling Reserve() before the loop. Calling Reserve() first can avoid unnecessary memory reallocations.

+

Currently, the check only detects following kinds of loops with a single statement body:

+
    +
  • Counter-based for loops start with 0:
  • +
+
std::vector<int> v;
+for (int i = 0; i < n; ++i) {
+  v.push_back(n);
+  // This will trigger the warning since the push_back may cause multiple
+  // memory reallocations in v. This can be avoid by inserting a 'reserve(n)'
+  // statement before the for statement.
+}
+
+SomeProto p;
+for (int i = 0; i < n; ++i) {
+  p.add_xxx(n);
+  // This will trigger the warning since the add_xxx may cause multiple memory
+  // reallocations. This can be avoid by inserting a
+  // 'p.mutable_xxx().Reserve(n)' statement before the for statement.
+}
+
    +
  • For-range loops like for (range-declaration : range_expression), the type of range_expression can be std::vector, std::array, std::deque, std::set, std::unordered_set, std::map, std::unordered_set:
  • +
+
std::vector<int> data;
+std::vector<int> v;
+
+for (auto element : data) {
+  v.push_back(element);
+  // This will trigger the warning since the 'push_back' may cause multiple
+  // memory reallocations in v. This can be avoid by inserting a
+  // 'reserve(data.size())' statement before the for statement.
+}
+
Options
+

VectorLikeClasses

+

Semicolon-separated list of names of vector-like classes. By default only ::std::vector is considered.

+

EnableProto

+

When true, the check will also warn on inefficient operations for proto repeated fields. Otherwise, the check only warns on inefficient vector operations. Default is false.

+

(Clang-Tidy original name: performance-inefficient-vector-operation)

+ + +#### Move Const Arg {#CT_PRF_MCA} +

The check warns

+
    +
  • if std::move() is called with a constant argument,
  • +
  • if std::move() is called with an argument of a trivially-copyable type,
  • +
  • if the result of std::move() is passed as a const reference argument.
  • +
+

In all three cases, the check will suggest a fix that removes the std::move().

+

Here are examples of each of the three cases:

+
const string s;
+return std::move(s);  // Warning: std::move of the const variable has no effect
+
+int x;
+return std::move(x);  // Warning: std::move of the variable of a trivially-copyable type has no effect
+
+void f(const string &s);
+string s;
+f(std::move(s));  // Warning: passing result of std::move as a const reference argument; no move will actually happen
+
Options
+

CheckTriviallyCopyableMove

+

If true, enables detection of trivially copyable types that do not have a move constructor. Default is true.

+

(Clang-Tidy original name: performance-move-const-arg)

+ + +#### Move Constructor Init {#CT_PRF_MCI} +

“cert-oop11-cpp” redirects here as an alias for this check.

+

The check flags user-defined move constructors that have a ctor-initializer initializing a member or base class through a copy constructor instead of a move constructor.

+
Options
+

IncludeStyle

+

A string specifying which include-style is used, llvm or google. Default is llvm.

+

(Clang-Tidy original name: performance-move-constructor-init)

+ + +#### No Automatic Move {#CT_PRF_NAM} +

Finds local variables that cannot be automatically moved due to constness.

+

Under certain conditions, local values are automatically moved out when returning from a function. A common mistake is to declare local lvalue variables const, which prevents the move.

+

Example [1]:

+
StatusOr<std::vector<int>> Cool() {
+  std::vector<int> obj = ...;
+  return obj;  // calls StatusOr::StatusOr(std::vector<int>&&)
+}
+
+StatusOr<std::vector<int>> NotCool() {
+  const std::vector<int> obj = ...;
+  return obj;  // calls `StatusOr::StatusOr(const std::vector<int>&)`
+}
+

The former version (Cool) should be preferred over the latter (Uncool) as it will avoid allocations and potentially large memory copies.

+
Semantics
+

In the example above, StatusOr::StatusOr(T&&) have the same semantics as long as the copy and move constructors for T have the same semantics. Note that there is no guarantee that S::S(T&&) and S::S(const T&) have the same semantics for any single S, so we’re not providing automated fixes for this check, and judgement should be exerted when making the suggested changes.

+
-Wreturn-std-move
+

Another case where the move cannot happen is the following:

+
StatusOr<std::vector<int>> Uncool() {
+  std::vector<int>&& obj = ...;
+  return obj;  // calls `StatusOr::StatusOr(const std::vector<int>&)`
+}
+

In that case the fix is more consensual: just return std::move(obj). This is handled by the -Wreturn-std-move warning.

+

(Clang-Tidy original name: performance-no-automatic-move)

+ + +#### No Int To Ptr {#CT_PRF_NITP} +

Diagnoses every integer to pointer cast.

+

While casting an (integral) pointer to an integer is obvious - you just get the integral value of the pointer, casting an integer to an (integral) pointer is deceivingly different. While you will get a pointer with that integral value, if you got that integral value via a pointer-to-integer cast originally, the new pointer will lack the provenance information from the original pointer.

+

So while (integral) pointer to integer casts are effectively no-ops, and are transparent to the optimizer, integer to (integral) pointer casts are NOT transparent, and may conceal information from optimizer.

+

While that may be the intention, it is not always so. For example, let’s take a look at a routine to align the pointer up to the multiple of 16: The obvious, naive implementation for that is:

+
char* src(char* maybe_underbiased_ptr) {
+  uintptr_t maybe_underbiased_intptr = (uintptr_t)maybe_underbiased_ptr;
+  uintptr_t aligned_biased_intptr = maybe_underbiased_intptr + 15;
+  uintptr_t aligned_intptr = aligned_biased_intptr & (~15);
+  return (char*)aligned_intptr; // warning: avoid integer to pointer casts [performance-no-int-to-ptr]
+}
+

The check will rightfully diagnose that cast.

+

But when provenance concealment is not the goal of the code, but an accident, this example can be rewritten as follows, without using integer to pointer cast:

+
char*
+tgt(char* maybe_underbiased_ptr) {
+    uintptr_t maybe_underbiased_intptr = (uintptr_t)maybe_underbiased_ptr;
+    uintptr_t aligned_biased_intptr = maybe_underbiased_intptr + 15;
+    uintptr_t aligned_intptr = aligned_biased_intptr & (~15);
+    uintptr_t bias = aligned_intptr - maybe_underbiased_intptr;
+    return maybe_underbiased_ptr + bias;
+}
+

(Clang-Tidy original name: performance-no-int-to-ptr)

+ + +#### Noexcept Move Constructor {#CT_PRF_NMC} +

The check flags user-defined move constructors and assignment operators not marked with noexcept or marked with noexcept(expr) where expr evaluates to false (but is not a false literal itself).

+

Move constructors of all the types used with STL containers, for example, need to be declared noexcept. Otherwise STL will choose copy constructors instead. The same is valid for move assignment operations.

+

(Clang-Tidy original name: performance-noexcept-move-constructor)

+ + +#### Trivially Destructible {#CT_PRF_TD} +

Finds types that could be made trivially-destructible by removing out-of-line defaulted destructor declarations.

+
struct A: TrivialType {
+  ~A(); // Makes A non-trivially-destructible.
+  TrivialType trivial_fields;
+};
+A::~A() = default;
+

(Clang-Tidy original name: performance-trivially-destructible)

+ + +#### Type Promotion In Math Fn {#CT_PRF_TPIMF} +

Finds calls to C math library functions (from math.h or, in C++, cmath) with implicit float to double promotions.

+

For example, warns on ::sin(0.f), because this funciton’s parameter is a double. You probably meant to call std::sin(0.f) (in C++), or sinf(0.f) (in C).

+
float a;
+asin(a);
+
+// becomes
+
+float a;
+std::asin(a);
+

(Clang-Tidy original name: performance-type-promotion-in-math-fn)

+ + +#### Unnecessary Copy Initialization {#CT_PRF_UCI} +

Finds local variable declarations that are initialized using the copy constructor of a non-trivially-copyable type but it would suffice to obtain a const reference.

+

The check is only applied if it is safe to replace the copy by a const reference. This is the case when the variable is const qualified or when it is only used as a const, i.e. only const methods or operators are invoked on it, or it is used as const reference or value argument in constructors or function calls.

+

Example:

+
const string& constReference();
+void Function() {
+  // The warning will suggest making this a const reference.
+  const string UnnecessaryCopy = constReference();
+}
+
+struct Foo {
+  const string& name() const;
+};
+void Function(const Foo& foo) {
+  // The warning will suggest making this a const reference.
+  string UnnecessaryCopy1 = foo.name();
+  UnnecessaryCopy1.find("bar");
+
+  // The warning will suggest making this a const reference.
+  string UnnecessaryCopy2 = UnnecessaryCopy1;
+  UnnecessaryCopy2.find("bar");
+}
+
Options
+

AllowedTypes

+

A semicolon-separated list of names of types allowed to be initialized by copying. Regular expressions are accepted, e.g. [Rr]ef(erence)?$ matches every type with suffix Ref, ref, Reference and reference. The default is empty.

+

(Clang-Tidy original name: performance-unnecessary-copy-initialization)

+ + +#### Unnecessary Value Param {#CT_PRF_UVP} +

Flags value parameter declarations of expensive to copy types that are copied for each invocation but it would suffice to pass them by const reference.

+

The check is only applied to parameters of types that are expensive to copy which means they are not trivially copyable or have a non-trivial copy constructor or destructor.

+

To ensure that it is safe to replace the value parameter with a const reference the following heuristic is employed:

+
    +
  1. the parameter is const qualified;
  2. +
  3. the parameter is not const, but only const methods or operators are invoked on it, or it is used as const reference or value argument in constructors or function calls.
  4. +
+

Example:

+
void f(const string Value) {
+  // The warning will suggest making Value a reference.
+}
+
+void g(ExpensiveToCopy Value) {
+  // The warning will suggest making Value a const reference.
+  Value.ConstMethd();
+  ExpensiveToCopy Copy(Value);
+}
+

If the parameter is not const, only copied or assigned once and has a non-trivial move-constructor or move-assignment operator respectively the check will suggest to move it.

+

Example:

+
void setValue(string Value) {
+  Field = Value;
+}
+

Will become:

+
#include <utility>
+
+void setValue(string Value) {
+  Field = std::move(Value);
+}
+
Options
+

IncludeStyle

+

A string specifying which include-style is used, llvm or google. Default is llvm.

+

AllowedTypes

+

A semicolon-separated list of names of types allowed to be passed by value. Regular expressions are accepted, e.g. [Rr]ef(erence)?$ matches every type with suffix Ref, ref, Reference and reference. The default is empty.

+

(Clang-Tidy original name: performance-unnecessary-value-param)

+ + +### Portability + +#### Restrict System Includes {#CT_PRT_RSI} +

Checks to selectively allow or disallow a configurable list of system headers.

+

For example:

+

In order to only allow zlib.h from the system you would set the options to -*,zlib.h.

+
#include <curses.h>       // Bad: disallowed system header.
+#include <openssl/ssl.h>  // Bad: disallowed system header.
+#include <zlib.h>         // Good: allowed system header.
+#include "src/myfile.h"   // Good: non-system header always allowed.
+

In order to allow everything except zlib.h from the system you would set the options to *,-zlib.h.

+
#include <curses.h>       // Good: allowed system header.
+#include <openssl/ssl.h>  // Good: allowed system header.
+#include <zlib.h>         // Bad: disallowed system header.
+#include "src/myfile.h"   // Good: non-system header always allowed.
+

Since the options support globbing you can use wildcarding to allow groups of headers.

+

-,openssl/.h will allow all openssl headers but disallow any others.

+
#include <curses.h>       // Bad: disallowed system header.
+#include <openssl/ssl.h>  // Good: allowed system header.
+#include <openssl/rsa.h>  // Good: allowed system header.
+#include <zlib.h>         // Bad: disallowed system header.
+#include "src/myfile.h"   // Good: non-system header always allowed.
+
Options
+

Includes

+

A string containing a comma separated glob list of allowed include filenames. Similar to the -checks glob list for running clang-tidy itself, the two wildcard characters are * and -, to include and exclude globs, respectively. The default is *, which allows all includes.

+

(Clang-Tidy original name: portability-restrict-system-includes)

+ + +#### Simd Intrinsics {#CT_PRT_SI} +

Finds SIMD intrinsics calls and suggests std::experimental::simd (P0214) alternatives.

+

If the option Suggest is set to true, for

+
_mm_add_epi32(a, b); // x86
+vec_add(a, b);       // Power
+

the check suggests an alternative: operator+ on std::experimental::simd objects.

+

Otherwise, it just complains the intrinsics are non-portable (and there are P0214 alternatives).

+

Many architectures provide SIMD operations (e.g. x86 SSE/AVX, Power AltiVec/VSX, ARM NEON). It is common that SIMD code implementing the same algorithm, is written in multiple target-dispatching pieces to optimize for different architectures or micro-architectures.

+

The C++ standard proposal P0214 and its extensions cover many common SIMD operations. By migrating from target-dependent intrinsics to P0214 operations, the SIMD code can be simplified and pieces for different targets can be unified.

+

Refer to P0214 for introduction and motivation for the data-parallel standard library.

+
Options
+

Suggest

+

If this option is set to true (default is false), the check will suggest P0214 alternatives, otherwise it only points out the intrinsic function is non-portable.

+

Std

+

The namespace used to suggest P0214 alternatives. If not specified, std:: for -std=c++20 and std::experimental:: for -std=c++11.

+

(Clang-Tidy original name: portability-simd-intrinsics)

+ + +### Readability + +#### Avoid Const Params In Decls {#CT_RDB_ACPID} +

Checks whether a function declaration has parameters that are top level const.

+

const values in declarations do not affect the signature of a function, so they should not be put there.

+

Examples:

+
void f(const string);   // Bad: const is top level.
+void f(const string&);  // Good: const is not top level.
+

(Clang-Tidy original name: readability-avoid-const-params-in-decls)

+ + +#### Braces Around Statements {#CT_RDB_BAS} +

google-readability-braces-around-statements redirects here as an alias for this check.

+

Checks that bodies of if statements and loops (for, do while, and while) are inside braces.

+

Before:

+
if (condition)
+  statement;
+

After:

+
if (condition) {
+  statement;
+}
+
Options
+

ShortStatementLines

+

Defines the minimal number of lines that the statement should have in order to trigger this check.

+

The number of lines is counted from the end of condition or initial keyword (do/else) until the last line of the inner statement. Default value 0 means that braces will be added to all statements (not having them already).

+

(Clang-Tidy original name: readability-braces-around-statements)

+ + +#### Const Return Type {#CT_RDB_CRT} +

Checks for functions with a const-qualified return type and recommends removal of the const keyword. Such use of const is usually superfluous, and can prevent valuable compiler optimizations. Does not (yet) fix trailing return types.

+

Examples:

+
const int foo();
+const Clazz foo();
+Clazz *const foo();
+

Note that this applies strictly to top-level qualification, which excludes pointers or references to const values. For example, these are fine:

+
const int* foo();
+const int& foo();
+const Clazz* foo();
+

(Clang-Tidy original name: readability-const-return-type)

+ + +#### Container Size Empty {#CT_RDB_CSE} +

Checks whether a call to the size() method can be replaced with a call to empty().

+

The emptiness of a container should be checked using the empty() method instead of the size() method. It is not guaranteed that size() is a constant-time function, and it is generally more efficient and also shows clearer intent to use empty(). Furthermore some containers may implement the empty() method but not implement the size() method. Using empty() whenever possible makes it easier to switch to another container in the future.

+

The check issues warning if a container has size() and empty() methods matching following signatures:

+
size_type size() const;
+bool empty() const;
+

size_type can be any kind of integer type.

+

(Clang-Tidy original name: readability-container-size-empty)

+ + +#### Convert Member Functions To Static {#CT_RDB_CMFTS} +

Finds non-static member functions that can be made static because the functions don’t use this.

+

After applying modifications as suggested by the check, running the check again might find more opportunities to mark member functions static.

+

After making a member function static, you might want to run the check readability-static-accessed-through-instance to replace calls like Instance.method() by Class::method().

+

(Clang-Tidy original name: readability-convert-member-functions-to-static)

+ + +#### Delete Null Pointer {#CT_RDB_DNP} +

Checks the if statements where a pointer’s existence is checked and then deletes the pointer. The check is unnecessary as deleting a null pointer has no effect.

+
int *p;
+if (p)
+  delete p;
+

(Clang-Tidy original name: readability-delete-null-pointer)

+ + +#### Deleted Default {#CT_RDB_DD} +

Checks that constructors and assignment operators marked as = default are not actually deleted by the compiler.

+
class Example {
+public:
+  // This constructor is deleted because I is missing a default value.
+  Example() = default;
+  // This is fine.
+  Example(const Example& Other) = default;
+  // This operator is deleted because I cannot be assigned (it is const).
+  Example& operator=(const Example& Other) = default;
+
+private:
+  const int I;
+};
+

(Clang-Tidy original name: readability-deleted-default)

+ + +#### Else After Return {#CT_RDB_EAR} +

LLVM Coding Standards advises to reduce indentation where possible and where it makes understanding code easier. Early exit is one of the suggested enforcements of that. Please do not use else or else if after something that interrupts control flow - like return, break, continue, throw.

+

The following piece of code illustrates how the check works. This piece of code:

+
void foo(int Value) {
+  int Local = 0;
+  for (int i = 0; i < 42; i++) {
+    if (Value == 1) {
+      return;
+    } else {
+      Local++;
+    }
+
+    if (Value == 2)
+      continue;
+    else
+      Local++;
+
+    if (Value == 3) {
+      throw 42;
+    } else {
+      Local++;
+    }
+  }
+}
+

Would be transformed into:

+
void foo(int Value) {
+  int Local = 0;
+  for (int i = 0; i < 42; i++) {
+    if (Value == 1) {
+      return;
+    }
+    Local++;
+
+    if (Value == 2)
+      continue;
+    Local++;
+
+    if (Value == 3) {
+      throw 42;
+    }
+    Local++;
+  }
+}
+
Options
+

WarnOnUnfixable

+

When true, emit a warning for cases where the check can’t output a Fix-It. These can occur with declarations inside the else branch that would have an extended lifetime if the else branch was removed. Default value is true.

+

WarnOnConditionVariables

+

When true, the check will attempt to refactor a variable defined inside the condition of the if statement that is used in the else branch defining them just before the if statement. This can only be done if the if statement is the last statement in its parents scope. Default value is true.

+
LLVM alias
+

There is an alias of this check called llvm-else-after-return. In that version the options WarnOnUnfixable and WarnOnConditionVariables are both set to false by default.

+

This check helps to enforce this LLVM Coding Standards recommendation.

+

(Clang-Tidy original name: readability-else-after-return)

+ + +#### Function Cognitive Complexity {#CT_RDB_FCC} +

Checks function Cognitive Complexity metric.

+

The metric is implemented as per the COGNITIVE COMPLEXITY by SonarSource specification version 1.2 (19 April 2017).

+
Options
+

Threshold

+

Flag functions with Cognitive Complexity exceeding this number. The default is 25.

+
Building blocks
+

There are three basic building blocks of a Cognitive Complexity metric:

+
Increment
+

The following structures increase the function’s Cognitive Complexity metric (by 1):

+
    +
  • Conditional operators:

    +
      +
    • if()
    • +
    • else if()
    • +
    • else
    • +
    • cond ? true : false
    • +
  • +
  • switch()

  • +
  • Loops:

    +
      +
    • for()
    • +
    • C++11 range-based for()
    • +
    • while()
    • +
    • do while()
    • +
  • +
  • catch ()

  • +
  • goto LABEL, goto *(&&LABEL)),

  • +
  • sequences of binary logical operators:

    +
      +
    • boolean1 || boolean2
    • +
    • boolean1 && boolean2
    • +
  • +
+
Nesting level
+

While by itself the nesting level not change the function’s Cognitive Complexity metric, it is tracked, and is used by the next, third building block. The following structures increase the nesting level (by 1):

+
    +
  • Conditional operators:

    +
      +
    • if()
    • +
    • else if()
    • +
    • else
    • +
    • cond ? true : false
    • +
  • +
  • switch()

  • +
  • Loops:

    +
      +
    • for()
    • +
    • C++11 range-based for()
    • +
    • while()
    • +
    • do while()
    • +
  • +
  • catch ()

  • +
  • Nested functions:

    +
      +
    • C++11 Lambda
    • +
    • Nested class
    • +
    • Nested struct
    • +
  • +
  • GNU statement expression

  • +
  • Apple Block Declaration

  • +
+
Nesting increment
+

This is where the previous basic building block, Nesting level, matters. The following structures increase the function’s Cognitive Complexity metric by the current Nesting level:

+
    +
  • Conditional operators:

    +
      +
    • if()
    • +
    • cond ? true : false
    • +
  • +
  • switch()

  • +
  • Loops:

    +
      +
    • for()
    • +
    • C++11 range-based for()
    • +
    • while()
    • +
    • do while()
    • +
  • +
  • catch ()

  • +
+
Examples
+

The simplest case. This function has Cognitive Complexity of 0.

+
void function0() {}
+

Slightly better example. This function has Cognitive Complexity of 1.

+
int function1(bool var) {
+  if(var) // +1, nesting level +1
+    return 42;
+  return 0;
+}
+

Full example. This function has Cognitive Complexity of 3.

+
int function3(bool var1, bool var2) {
+  if(var1) { // +1, nesting level +1
+    if(var2)  // +2 (1 + current nesting level of 1), nesting level +1
+      return 42;
+  }
+
+  return 0;
+}
+
Limitations
+

The metric is implemented with two notable exceptions:

+
    +
  • preprocessor conditionals (#ifdef, #if, #elif, #else, #endif) are not accounted for.
  • +
  • each method in a recursion cycle is not accounted for. It can’t be fully implemented, because cross-translational-unit analysis would be needed, which is currently not possible in clang-tidy.
  • +
+

(Clang-Tidy original name: readability-function-cognitive-complexity)

+ + +#### Function Size {#CT_RDB_FS} +

google-readability-function-size redirects here as an alias for this check.

+

Checks for large functions based on various metrics.

+
Options
+

LineThreshold

+

Flag functions exceeding this number of lines. The default is -1 (ignore the number of lines).

+

StatementThreshold

+

Flag functions exceeding this number of statements. This may differ significantly from the number of lines for macro-heavy code. The default is 800.

+

BranchThreshold

+

Flag functions exceeding this number of control statements. The default is -1 (ignore the number of branches).

+

ParameterThreshold

+

Flag functions that exceed a specified number of parameters. The default is -1 (ignore the number of parameters).

+

NestingThreshold

+

Flag compound statements which create next nesting level after NestingThreshold. This may differ significantly from the expected value for macro-heavy code. The default is -1 (ignore the nesting level).

+

VariableThreshold

+

Flag functions exceeding this number of variables declared in the body. The default is -1 (ignore the number of variables). Please note that function parameters and variables declared in lambdas, GNU Statement Expressions, and nested class inline functions are not counted.

+

(Clang-Tidy original name: readability-function-size)

+ + +#### Identifier Naming {#CT_RDB_IN} +

Checks for identifiers naming style mismatch.

+

This check will try to enforce coding guidelines on the identifiers naming. It supports one of the following casing types and tries to convert from one to another if a mismatch is detected

+

Casing types include:

+
    +
  • lower_case,
  • +
  • UPPER_CASE,
  • +
  • camelBack,
  • +
  • CamelCase,
  • +
  • camel_Snake_Back,
  • +
  • Camel_Snake_Case,
  • +
  • aNy_CasE.
  • +
+

It also supports a fixed prefix and suffix that will be prepended or appended to the identifiers, regardless of the casing.

+

Many configuration options are available, in order to be able to create different rules for different kinds of identifiers. In general, the rules are falling back to a more generic rule if the specific case is not configured.

+

The naming of virtual methods is reported where they occur in the base class, but not where they are overridden, as it can’t be fixed locally there. This also applies for pseudo-override patterns like CRTP.

+
Options
+

The following options are describe below:

+ +

AbstractClassCase

+

When defined, the check will ensure abstract class names conform to the selected casing.

+

AbstractClassPrefix

+

When defined, the check will ensure abstract class names will add the prefixed with the given value (regardless of casing).

+

AbstractClassIgnoredRegexp

+

Identifier naming checks won’t be enforced for abstract class names matching this regular expression.

+

AbstractClassSuffix

+

When defined, the check will ensure abstract class names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • AbstractClassCase of lower_case
  • +
  • AbstractClassPrefix of pre_
  • +
  • AbstractClassSuffix of _post
  • +
+

Identifies and/or transforms abstract class names as follows:

+

Before:

+
class ABSTRACT_CLASS {
+public:
+  ABSTRACT_CLASS();
+};
+

After:

+
class pre_abstract_class_post {
+public:
+  pre_abstract_class_post();
+};
+

AggressiveDependentMemberLookup

+

When set to true the check will look in dependent base classes for dependent member references that need changing. This can lead to errors with template specializations so the default value is false.

+

For example using values of:

+
    +
  • ClassMemberCase of lower_case
  • +
+

Before:

+
template <typename T>
+struct Base {
+  T BadNamedMember;
+};
+
+template <typename T>
+struct Derived : Base<T> {
+  void reset() {
+    this->BadNamedMember = 0;
+  }
+};
+

After if AggressiveDependentMemberLookup is false:

+
template <typename T>
+struct Base {
+  T bad_named_member;
+};
+
+template <typename T>
+struct Derived : Base<T> {
+  void reset() {
+    this->BadNamedMember = 0;
+  }
+};
+

After if AggressiveDependentMemberLookup is true:

+
template <typename T>
+struct Base {
+  T bad_named_member;
+};
+
+template <typename T>
+struct Derived : Base<T> {
+  void reset() {
+    this->bad_named_member = 0;
+  }
+};
+

ClassCase

+

When defined, the check will ensure class names conform to the selected casing.

+

ClassPrefix

+

When defined, the check will ensure class names will add the prefixed with the given value (regardless of casing).

+

ClassIgnoredRegexp

+

Identifier naming checks won’t be enforced for class names matching this regular expression.

+

ClassSuffix

+

When defined, the check will ensure class names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • ClassCase of lower_case
  • +
  • ClassPrefix of pre_
  • +
  • ClassSuffix of _post
  • +
+

Identifies and/or transforms class names as follows:

+

Before:

+
class FOO {
+public:
+  FOO();
+  ~FOO();
+};
+

After:

+
class pre_foo_post {
+public:
+  pre_foo_post();
+  ~pre_foo_post();
+};
+

ClassConstantCase

+

When defined, the check will ensure class constant names conform to the selected casing.

+

ClassConstantPrefix

+

When defined, the check will ensure class constant names will add the prefixed with the given value (regardless of casing).

+

ClassConstantIgnoredRegexp

+

Identifier naming checks won’t be enforced for class constant names matching this regular expression.

+

ClassConstantSuffix

+

When defined, the check will ensure class constant names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • ClassConstantCase of lower_case
  • +
  • ClassConstantPrefix of pre_
  • +
  • ClassConstantSuffix of _post
  • +
+

Identifies and/or transforms class constant names as follows:

+

Before:

+
class FOO {
+public:
+  static const int CLASS_CONSTANT;
+};
+

After:

+
class FOO {
+public:
+  static const int pre_class_constant_post;
+};
+

ClassMemberCase

+

When defined, the check will ensure class member names conform to the selected casing.

+

ClassMemberPrefix

+

When defined, the check will ensure class member names will add the prefixed with the given value (regardless of casing).

+

ClassMemberIgnoredRegexp

+

Identifier naming checks won’t be enforced for class member names matching this regular expression.

+

ClassMemberSuffix

+

When defined, the check will ensure class member names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • ClassMemberCase of lower_case
  • +
  • ClassMemberPrefix of pre_
  • +
  • ClassMemberSuffix of _post
  • +
+

Identifies and/or transforms class member names as follows:

+

Before:

+
class FOO {
+public:
+  static int CLASS_CONSTANT;
+};
+

After:

+
class FOO {
+public:
+  static int pre_class_constant_post;
+};
+

ClassMethodCase

+

When defined, the check will ensure class method names conform to the selected casing.

+

ClassMethodPrefix

+

When defined, the check will ensure class method names will add the prefixed with the given value (regardless of casing).

+

ClassMethodIgnoredRegexp

+

Identifier naming checks won’t be enforced for class method names matching this regular expression.

+

ClassMethodSuffix

+

When defined, the check will ensure class method names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • ClassMethodCase of lower_case
  • +
  • ClassMethodPrefix of pre_
  • +
  • ClassMethodSuffix of _post
  • +
+

Identifies and/or transforms class method names as follows:

+

Before:

+
class FOO {
+public:
+  int CLASS_MEMBER();
+};
+

After:

+
class FOO {
+public:
+  int pre_class_member_post();
+};
+

ConstantCase

+

When defined, the check will ensure constant names conform to the selected casing.

+

ConstantPrefix

+

When defined, the check will ensure constant names will add the prefixed with the given value (regardless of casing).

+

ConstantIgnoredRegexp

+

Identifier naming checks won’t be enforced for constant names matching this regular expression.

+

ConstantSuffix

+

When defined, the check will ensure constant names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • ConstantCase of lower_case
  • +
  • ConstantPrefix of pre_
  • +
  • ConstantSuffix of _post
  • +
+

Identifies and/or transforms constant names as follows:

+

Before:

+
void function() { unsigned const MyConst_array[] = {1, 2, 3}; }
+

After:

+
void function() { unsigned const pre_myconst_array_post[] = {1, 2, 3}; }
+

ConstantMemberCase

+

When defined, the check will ensure constant member names conform to the selected casing.

+

ConstantMemberPrefix

+

When defined, the check will ensure constant member names will add the prefixed with the given value (regardless of casing).

+

ConstantMemberIgnoredRegexp

+

Identifier naming checks won’t be enforced for constant member names matching this regular expression.

+

ConstantMemberSuffix

+

When defined, the check will ensure constant member names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • ConstantMemberCase of lower_case
  • +
  • ConstantMemberPrefix of pre_
  • +
  • ConstantMemberSuffix of _post
  • +
+

Identifies and/or transforms constant member names as follows:

+

Before:

+
class Foo {
+  char const MY_ConstMember_string[4] = "123";
+}
+

After:

+
class Foo {
+  char const pre_my_constmember_string_post[4] = "123";
+}
+

ConstantParameterCase

+

When defined, the check will ensure constant parameter names conform to the selected casing.

+

ConstantParameterPrefix

+

When defined, the check will ensure constant parameter names will add the prefixed with the given value (regardless of casing).

+

ConstantParameterIgnoredRegexp

+

Identifier naming checks won’t be enforced for constant parameter names matching this regular expression.

+

ConstantParameterSuffix

+

When defined, the check will ensure constant parameter names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • ConstantParameterCase of lower_case
  • +
  • ConstantParameterPrefix of pre_
  • +
  • ConstantParameterSuffix of _post
  • +
+

Identifies and/or transforms constant parameter names as follows:

+

Before:

+
void GLOBAL_FUNCTION(int PARAMETER_1, int const CONST_parameter);
+

After:

+
void GLOBAL_FUNCTION(int PARAMETER_1, int const pre_const_parameter_post);
+

ConstantPointerParameterCase

+

When defined, the check will ensure constant pointer parameter names conform to the selected casing.

+

ConstantPointerParameterPrefix

+

When defined, the check will ensure constant pointer parameter names will add the prefixed with the given value (regardless of casing).

+

ConstantPointerParameterIgnoredRegexp

+

Identifier naming checks won’t be enforced for constant pointer parameter names matching this regular expression.

+

ConstantPointerParameterSuffix

+

When defined, the check will ensure constant pointer parameter names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • ConstantPointerParameterCase of lower_case
  • +
  • ConstantPointerParameterPrefix of pre_
  • +
  • ConstantPointerParameterSuffix of _post
  • +
+

Identifies and/or transforms constant pointer parameter names as follows:

+

Before:

+
void GLOBAL_FUNCTION(int const *CONST_parameter);
+

After:

+
void GLOBAL_FUNCTION(int const *pre_const_parameter_post);
+

ConstexprFunctionCase

+

When defined, the check will ensure constexpr function names conform to the selected casing.

+

ConstexprFunctionPrefix

+

When defined, the check will ensure constexpr function names will add the prefixed with the given value (regardless of casing).

+

ConstexprFunctionIgnoredRegexp

+

Identifier naming checks won’t be enforced for constexpr function names matching this regular expression.

+

ConstexprFunctionSuffix

+

When defined, the check will ensure constexpr function names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • ConstexprFunctionCase of lower_case
  • +
  • ConstexprFunctionPrefix of pre_
  • +
  • ConstexprFunctionSuffix of _post
  • +
+

Identifies and/or transforms constexpr function names as follows:

+

Before:

+
constexpr int CE_function() { return 3; }
+

After:

+
constexpr int pre_ce_function_post() { return 3; }
+

ConstexprMethodCase

+

When defined, the check will ensure constexpr method names conform to the selected casing.

+

ConstexprMethodPrefix

+

When defined, the check will ensure constexpr method names will add the prefixed with the given value (regardless of casing).

+

ConstexprMethodIgnoredRegexp

+

Identifier naming checks won’t be enforced for constexpr method names matching this regular expression.

+

ConstexprMethodSuffix

+

When defined, the check will ensure constexpr method names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • ConstexprMethodCase of lower_case
  • +
  • ConstexprMethodPrefix of pre_
  • +
  • ConstexprMethodSuffix of _post
  • +
+

Identifies and/or transforms constexpr method names as follows:

+

Before:

+
class Foo {
+public:
+  constexpr int CST_expr_Method() { return 2; }
+}
+

After:

+
class Foo {
+public:
+  constexpr int pre_cst_expr_method_post() { return 2; }
+}
+

ConstexprVariableCase

+

When defined, the check will ensure constexpr variable names conform to the selected casing.

+

ConstexprVariablePrefix

+

When defined, the check will ensure constexpr variable names will add the prefixed with the given value (regardless of casing).

+

ConstexprVariableIgnoredRegexp

+

Identifier naming checks won’t be enforced for constexpr variable names matching this regular expression.

+

ConstexprVariableSuffix

+

When defined, the check will ensure constexpr variable names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • ConstexprVariableCase of lower_case
  • +
  • ConstexprVariablePrefix of pre_
  • +
  • ConstexprVariableSuffix of _post
  • +
+

Identifies and/or transforms constexpr variable names as follows:

+

Before:

+
constexpr int ConstExpr_variable = MyConstant;
+

After:

+
constexpr int pre_constexpr_variable_post = MyConstant;
+

EnumCase

+

When defined, the check will ensure enumeration names conform to the selected casing.

+

EnumPrefix

+

When defined, the check will ensure enumeration names will add the prefixed with the given value (regardless of casing).

+

EnumIgnoredRegexp

+

Identifier naming checks won’t be enforced for enumeration names matching this regular expression.

+

EnumSuffix

+

When defined, the check will ensure enumeration names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • EnumCase of lower_case
  • +
  • EnumPrefix of pre_
  • +
  • EnumSuffix of _post
  • +
+

Identifies and/or transforms enumeration names as follows:

+

Before:

+
enum FOO { One, Two, Three };
+

After:

+
enum pre_foo_post { One, Two, Three };
+

EnumConstantCase

+

When defined, the check will ensure enumeration constant names conform to the selected casing.

+

EnumConstantPrefix

+

When defined, the check will ensure enumeration constant names will add the prefixed with the given value (regardless of casing).

+

EnumConstantIgnoredRegexp

+

Identifier naming checks won’t be enforced for enumeration constant names matching this regular expression.

+

EnumConstantSuffix

+

When defined, the check will ensure enumeration constant names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • EnumConstantCase of lower_case
  • +
  • EnumConstantPrefix of pre_
  • +
  • EnumConstantSuffix of _post
  • +
+

Identifies and/or transforms enumeration constant names as follows:

+

Before:

+
enum FOO { One, Two, Three };
+

After:

+
enum FOO { pre_One_post, pre_Two_post, pre_Three_post };
+

FunctionCase

+

When defined, the check will ensure function names conform to the selected casing.

+

FunctionPrefix

+

When defined, the check will ensure function names will add the prefixed with the given value (regardless of casing).

+

FunctionIgnoredRegexp

+

Identifier naming checks won’t be enforced for function names matching this regular expression.

+

FunctionSuffix

+

When defined, the check will ensure function names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • FunctionCase of lower_case
  • +
  • FunctionPrefix of pre_
  • +
  • FunctionSuffix of _post
  • +
+

Identifies and/or transforms function names as follows:

+

Before:

+
char MY_Function_string();
+

After:

+
char pre_my_function_string_post();
+

GetConfigPerFile

+

When true the check will look for the configuration for where an identifier is declared. Useful for when included header files use a different style. Default value is true.

+

GlobalConstantCase

+

When defined, the check will ensure global constant names conform to the selected casing.

+

GlobalConstantPrefix

+

When defined, the check will ensure global constant names will add the prefixed with the given value (regardless of casing).

+

GlobalConstantIgnoredRegexp

+

Identifier naming checks won’t be enforced for global constant names matching this regular expression.

+

GlobalConstantSuffix

+

When defined, the check will ensure global constant names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • GlobalConstantCase of lower_case
  • +
  • GlobalConstantPrefix of pre_
  • +
  • GlobalConstantSuffix of _post
  • +
+

Identifies and/or transforms global constant names as follows:

+

Before:

+
unsigned const MyConstGlobal_array[] = {1, 2, 3};
+

After:

+
unsigned const pre_myconstglobal_array_post[] = {1, 2, 3};
+

GlobalConstantPointerCase

+

When defined, the check will ensure global constant pointer names conform to the selected casing.

+

GlobalConstantPointerPrefix

+

When defined, the check will ensure global constant pointer names will add the prefixed with the given value (regardless of casing).

+

GlobalConstantPointerIgnoredRegexp

+

Identifier naming checks won’t be enforced for global constant pointer names matching this regular expression.

+

GlobalConstantPointerSuffix

+

When defined, the check will ensure global constant pointer names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • GlobalConstantPointerCase of lower_case
  • +
  • GlobalConstantPointerPrefix of pre_
  • +
  • GlobalConstantPointerSuffix of _post
  • +
+

Identifies and/or transforms global constant pointer names as follows:

+

Before:

+
int *const MyConstantGlobalPointer = nullptr;
+

After:

+
int *const pre_myconstantglobalpointer_post = nullptr;
+

GlobalFunctionCase

+

When defined, the check will ensure global function names conform to the selected casing.

+

GlobalFunctionPrefix

+

When defined, the check will ensure global function names will add the prefixed with the given value (regardless of casing).

+

GlobalFunctionIgnoredRegexp

+

Identifier naming checks won’t be enforced for global function names matching this regular expression.

+

GlobalFunctionSuffix

+

When defined, the check will ensure global function names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • GlobalFunctionCase of lower_case
  • +
  • GlobalFunctionPrefix of pre_
  • +
  • GlobalFunctionSuffix of _post
  • +
+

Identifies and/or transforms global function names as follows:

+

Before:

+
void GLOBAL_FUNCTION(int PARAMETER_1, int const CONST_parameter);
+

After:

+
void pre_global_function_post(int PARAMETER_1, int const CONST_parameter);
+

GlobalPointerCase

+

When defined, the check will ensure global pointer names conform to the selected casing.

+

GlobalPointerPrefix

+

When defined, the check will ensure global pointer names will add the prefixed with the given value (regardless of casing).

+

GlobalPointerIgnoredRegexp

+

Identifier naming checks won’t be enforced for global pointer names matching this regular expression.

+

GlobalPointerSuffix

+

When defined, the check will ensure global pointer names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • GlobalPointerCase of lower_case
  • +
  • GlobalPointerPrefix of pre_
  • +
  • GlobalPointerSuffix of _post
  • +
+

Identifies and/or transforms global pointer names as follows:

+

Before:

+
int *GLOBAL3;
+

After:

+
int *pre_global3_post;
+

GlobalVariableCase

+

When defined, the check will ensure global variable names conform to the selected casing.

+

GlobalVariablePrefix

+

When defined, the check will ensure global variable names will add the prefixed with the given value (regardless of casing).

+

GlobalVariableIgnoredRegexp

+

Identifier naming checks won’t be enforced for global variable names matching this regular expression.

+

GlobalVariableSuffix

+

When defined, the check will ensure global variable names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • GlobalVariableCase of lower_case
  • +
  • GlobalVariablePrefix of pre_
  • +
  • GlobalVariableSuffix of _post
  • +
+

Identifies and/or transforms global variable names as follows:

+

Before:

+
int GLOBAL3;
+

After:

+
int pre_global3_post;
+

IgnoreMainLikeFunctions

+

When set to true functions that have a similar signature to main or wmain won’t enforce checks on the names of their parameters. Default value is false.

+

InlineNamespaceCase

+

When defined, the check will ensure inline namespaces names conform to the selected casing.

+

InlineNamespacePrefix

+

When defined, the check will ensure inline namespaces names will add the prefixed with the given value (regardless of casing).

+

InlineNamespaceIgnoredRegexp

+

Identifier naming checks won’t be enforced for inline namespaces names matching this regular expression.

+

InlineNamespaceSuffix

+

When defined, the check will ensure inline namespaces names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • InlineNamespaceCase of lower_case
  • +
  • InlineNamespacePrefix of pre_
  • +
  • InlineNamespaceSuffix of _post
  • +
+

Identifies and/or transforms inline namespaces names as follows:

+

Before:

+
namespace FOO_NS {
+inline namespace InlineNamespace {
+...
+}
+} // namespace FOO_NS
+

After:

+
namespace FOO_NS {
+inline namespace pre_inlinenamespace_post {
+...
+}
+} // namespace FOO_NS
+

LocalConstantCase

+

When defined, the check will ensure local constant names conform to the selected casing.

+

LocalConstantPrefix

+

When defined, the check will ensure local constant names will add the prefixed with the given value (regardless of casing).

+

LocalConstantIgnoredRegexp

+

Identifier naming checks won’t be enforced for local constant names matching this regular expression.

+

LocalConstantSuffix

+

When defined, the check will ensure local constant names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • LocalConstantCase of lower_case
  • +
  • LocalConstantPrefix of pre_
  • +
  • LocalConstantSuffix of _post
  • +
+

Identifies and/or transforms local constant names as follows:

+

Before:

+
void foo() { int const local_Constant = 3; }
+

After:

+
void foo() { int const pre_local_constant_post = 3; }
+

LocalConstantPointerCase

+

When defined, the check will ensure local constant pointer names conform to the selected casing.

+

LocalConstantPointerPrefix

+

When defined, the check will ensure local constant pointer names will add the prefixed with the given value (regardless of casing).

+

LocalConstantPointerIgnoredRegexp

+

Identifier naming checks won’t be enforced for local constant pointer names matching this regular expression.

+

LocalConstantPointerSuffix

+

When defined, the check will ensure local constant pointer names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • LocalConstantPointerCase of lower_case
  • +
  • LocalConstantPointerPrefix of pre_
  • +
  • LocalConstantPointerSuffix of _post
  • +
+

Identifies and/or transforms local constant pointer names as follows:

+

Before:

+
void foo() { int const *local_Constant = 3; }
+

After:

+
void foo() { int const *pre_local_constant_post = 3; }
+

LocalPointerCase

+

When defined, the check will ensure local pointer names conform to the selected casing.

+

LocalPointerPrefix

+

When defined, the check will ensure local pointer names will add the prefixed with the given value (regardless of casing).

+

LocalPointerIgnoredRegexp

+

Identifier naming checks won’t be enforced for local pointer names matching this regular expression.

+

LocalPointerSuffix

+

When defined, the check will ensure local pointer names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • LocalPointerCase of lower_case
  • +
  • LocalPointerPrefix of pre_
  • +
  • LocalPointerSuffix of _post
  • +
+

Identifies and/or transforms local pointer names as follows:

+

Before:

+
void foo() { int *local_Constant; }
+

After:

+
void foo() { int *pre_local_constant_post; }
+

LocalVariableCase

+

When defined, the check will ensure local variable names conform to the selected casing.

+

LocalVariablePrefix

+

When defined, the check will ensure local variable names will add the prefixed with the given value (regardless of casing).

+

LocalVariableIgnoredRegexp

+

Identifier naming checks won’t be enforced for local variable names matching this regular expression.

+

For example using values of:

+
    +
  • LocalVariableCase of CamelCase
  • +
  • LocalVariableIgnoredRegexp of
  • +
+

Will exclude variables with a length less than or equal to 2 from the camel case check applied to other variables.

+

LocalVariableSuffix

+

When defined, the check will ensure local variable names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • LocalVariableCase of lower_case
  • +
  • LocalVariablePrefix of pre_
  • +
  • LocalVariableSuffix of _post
  • +
+

Identifies and/or transforms local variable names as follows:

+

Before:

+
void foo() { int local_Constant; }
+

After:

+
void foo() { int pre_local_constant_post; }
+

MacroDefinitionCase

+

When defined, the check will ensure macro definitions conform to the selected casing.

+

MacroDefinitionPrefix

+

When defined, the check will ensure macro definitions will add the prefixed with the given value (regardless of casing).

+

MacroDefinitionIgnoredRegexp

+

Identifier naming checks won’t be enforced for macro definitions matching this regular expression.

+

MacroDefinitionSuffix

+

When defined, the check will ensure macro definitions will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • MacroDefinitionCase of lower_case
  • +
  • MacroDefinitionPrefix of pre_
  • +
  • MacroDefinitionSuffix of _post
  • +
+

Identifies and/or transforms macro definitions as follows:

+

Before:

+
#define MY_MacroDefinition
+

After:

+
#define pre_my_macro_definition_post
+

Note: This will not warn on builtin macros or macros defined on the command line using the -D flag.

+

MemberCase

+

When defined, the check will ensure member names conform to the selected casing.

+

MemberPrefix

+

When defined, the check will ensure member names will add the prefixed with the given value (regardless of casing).

+

MemberIgnoredRegexp

+

Identifier naming checks won’t be enforced for member names matching this regular expression.

+

MemberSuffix

+

When defined, the check will ensure member names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • MemberCase of lower_case
  • +
  • MemberPrefix of pre_
  • +
  • MemberSuffix of _post
  • +
+

Identifies and/or transforms member names as follows:

+

Before:

+
class Foo {
+  char MY_ConstMember_string[4];
+}
+

After:

+
class Foo {
+  char pre_my_constmember_string_post[4];
+}
+

MethodCase

+

When defined, the check will ensure method names conform to the selected casing.

+

MethodPrefix

+

When defined, the check will ensure method names will add the prefixed with the given value (regardless of casing).

+

MethodIgnoredRegexp

+

Identifier naming checks won’t be enforced for method names matching this regular expression.

+

MethodSuffix

+

When defined, the check will ensure method names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • MethodCase of lower_case
  • +
  • MethodPrefix of pre_
  • +
  • MethodSuffix of _post
  • +
+

Identifies and/or transforms method names as follows:

+

Before:

+
class Foo {
+  char MY_Method_string();
+}
+

After:

+
class Foo {
+  char pre_my_method_string_post();
+}
+

NamespaceCase

+

When defined, the check will ensure namespace names conform to the selected casing.

+

NamespacePrefix

+

When defined, the check will ensure namespace names will add the prefixed with the given value (regardless of casing).

+

NamespaceIgnoredRegexp

+

Identifier naming checks won’t be enforced for namespace names matching this regular expression.

+

NamespaceSuffix

+

When defined, the check will ensure namespace names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • NamespaceCase of lower_case
  • +
  • NamespacePrefix of pre_
  • +
  • NamespaceSuffix of _post
  • +
+

Identifies and/or transforms namespace names as follows:

+

Before:

+
namespace FOO_NS {
+...
+}
+

After:

+
namespace pre_foo_ns_post {
+...
+}
+

ParameterCase

+

When defined, the check will ensure parameter names conform to the selected casing.

+

ParameterPrefix

+

When defined, the check will ensure parameter names will add the prefixed with the given value (regardless of casing).

+

ParameterIgnoredRegexp

+

Identifier naming checks won’t be enforced for parameter names matching this regular expression.

+

ParameterSuffix

+

When defined, the check will ensure parameter names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • ParameterCase of lower_case
  • +
  • ParameterPrefix of pre_
  • +
  • ParameterSuffix of _post
  • +
+

Identifies and/or transforms parameter names as follows:

+

Before:

+
void GLOBAL_FUNCTION(int PARAMETER_1, int const CONST_parameter);
+

After:

+
void GLOBAL_FUNCTION(int pre_parameter_post, int const CONST_parameter);
+

ParameterPackCase

+

When defined, the check will ensure parameter pack names conform to the selected casing.

+

ParameterPackPrefix

+

When defined, the check will ensure parameter pack names will add the prefixed with the given value (regardless of casing).

+

ParameterPackIgnoredRegexp

+

Identifier naming checks won’t be enforced for parameter pack names matching this regular expression.

+

ParameterPackSuffix

+

When defined, the check will ensure parameter pack names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • ParameterPackCase of lower_case
  • +
  • ParameterPackPrefix of pre_
  • +
  • ParameterPackSuffix of _post
  • +
+

Identifies and/or transforms parameter pack names as follows:

+

Before:

+
template <typename... TYPE_parameters> {
+  void FUNCTION(int... TYPE_parameters);
+}
+

After:

+
template <typename... TYPE_parameters> {
+  void FUNCTION(int... pre_type_parameters_post);
+}
+

PointerParameterCase

+

When defined, the check will ensure pointer parameter names conform to the selected casing.

+

PointerParameterPrefix

+

When defined, the check will ensure pointer parameter names will add the prefixed with the given value (regardless of casing).

+

PointerParameterIgnoredRegexp

+

Identifier naming checks won’t be enforced for pointer parameter names matching this regular expression.

+

PointerParameterSuffix

+

When defined, the check will ensure pointer parameter names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • PointerParameterCase of lower_case
  • +
  • PointerParameterPrefix of pre_
  • +
  • PointerParameterSuffix of _post
  • +
+

Identifies and/or transforms pointer parameter names as follows:

+

Before:

+
void FUNCTION(int *PARAMETER);
+

After:

+
void FUNCTION(int *pre_parameter_post);
+

PrivateMemberCase

+

When defined, the check will ensure private member names conform to the selected casing.

+

PrivateMemberPrefix

+

When defined, the check will ensure private member names will add the prefixed with the given value (regardless of casing).

+

PrivateMemberIgnoredRegexp

+

Identifier naming checks won’t be enforced for private member names matching this regular expression.

+

PrivateMemberSuffix

+

When defined, the check will ensure private member names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • PrivateMemberCase of lower_case
  • +
  • PrivateMemberPrefix of pre_
  • +
  • PrivateMemberSuffix of _post
  • +
+

Identifies and/or transforms private member names as follows:

+

Before:

+
class Foo {
+private:
+  int Member_Variable;
+}
+

After:

+
class Foo {
+private:
+  int pre_member_variable_post;
+}
+

PrivateMethodCase

+

When defined, the check will ensure private method names conform to the selected casing.

+

PrivateMethodPrefix

+

When defined, the check will ensure private method names will add the prefixed with the given value (regardless of casing).

+

PrivateMethodIgnoredRegexp

+

Identifier naming checks won’t be enforced for private method names matching this regular expression.

+

PrivateMethodSuffix

+

When defined, the check will ensure private method names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • PrivateMethodCase of lower_case
  • +
  • PrivateMethodPrefix of pre_
  • +
  • PrivateMethodSuffix of _post
  • +
+

Identifies and/or transforms private method names as follows:

+

Before:

+
class Foo {
+private:
+  int Member_Method();
+}
+

After:

+
class Foo {
+private:
+  int pre_member_method_post();
+}
+

ProtectedMemberCase

+

When defined, the check will ensure protected member names conform to the selected casing.

+

ProtectedMemberPrefix

+

When defined, the check will ensure protected member names will add the prefixed with the given value (regardless of casing).

+

ProtectedMemberIgnoredRegexp

+

Identifier naming checks won’t be enforced for protected member names matching this regular expression.

+

ProtectedMemberSuffix

+

When defined, the check will ensure protected member names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • ProtectedMemberCase of lower_case
  • +
  • ProtectedMemberPrefix of pre_
  • +
  • ProtectedMemberSuffix of _post
  • +
+

Identifies and/or transforms protected member names as follows:

+

Before:

+
class Foo {
+protected:
+  int Member_Variable;
+}
+

After:

+
class Foo {
+protected:
+  int pre_member_variable_post;
+}
+

ProtectedMethodCase

+

When defined, the check will ensure protected method names conform to the selected casing.

+

ProtectedMethodPrefix

+

When defined, the check will ensure protected method names will add the prefixed with the given value (regardless of casing).

+

ProtectedMethodIgnoredRegexp

+

Identifier naming checks won’t be enforced for protected method names matching this regular expression.

+

ProtectedMethodSuffix

+

When defined, the check will ensure protected method names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • ProtectedMethodCase of lower_case
  • +
  • ProtectedMethodPrefix of pre_
  • +
  • ProtectedMethodSuffix of _post
  • +
+

Identifies and/or transforms protect method names as follows:

+

Before:

+
class Foo {
+protected:
+  int Member_Method();
+}
+

After:

+
class Foo {
+protected:
+  int pre_member_method_post();
+}
+

PublicMemberCase

+

When defined, the check will ensure public member names conform to the selected casing.

+

PublicMemberPrefix

+

When defined, the check will ensure public member names will add the prefixed with the given value (regardless of casing).

+

PublicMemberIgnoredRegexp

+

Identifier naming checks won’t be enforced for public member names matching this regular expression.

+

PublicMemberSuffix

+

When defined, the check will ensure public member names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • PublicMemberCase of lower_case
  • +
  • PublicMemberPrefix of pre_
  • +
  • PublicMemberSuffix of _post
  • +
+

Identifies and/or transforms public member names as follows:

+

Before:

+
class Foo {
+public:
+  int Member_Variable;
+}
+

After:

+
class Foo {
+public:
+  int pre_member_variable_post;
+}
+

PublicMethodCase

+

When defined, the check will ensure public method names conform to the selected casing.

+

PublicMethodPrefix

+

When defined, the check will ensure public method names will add the prefixed with the given value (regardless of casing).

+

PublicMethodIgnoredRegexp

+

Identifier naming checks won’t be enforced for public method names matching this regular expression.

+

PublicMethodSuffix

+

When defined, the check will ensure public method names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • PublicMethodCase of lower_case
  • +
  • PublicMethodPrefix of pre_
  • +
  • PublicMethodSuffix of _post
  • +
+

Identifies and/or transforms public method names as follows:

+

Before:

+
class Foo {
+public:
+  int Member_Method();
+}
+

After:

+
class Foo {
+public:
+  int pre_member_method_post();
+}
+

ScopedEnumConstantCase

+

When defined, the check will ensure scoped enum constant names conform to the selected casing.

+

ScopedEnumConstantPrefix

+

When defined, the check will ensure scoped enum constant names will add the prefixed with the given value (regardless of casing).

+

ScopedEnumConstantIgnoredRegexp

+

Identifier naming checks won’t be enforced for scoped enum constant names matching this regular expression.

+

ScopedEnumConstantSuffix

+

When defined, the check will ensure scoped enum constant names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • ScopedEnumConstantCase of lower_case
  • +
  • ScopedEnumConstantPrefix of pre_
  • +
  • ScopedEnumConstantSuffix of _post
  • +
+

Identifies and/or transforms enumeration constant names as follows:

+

Before:

+
enum class FOO { One, Two, Three };
+

After:

+
enum class FOO { pre_One_post, pre_Two_post, pre_Three_post };
+

StaticConstantCase

+

When defined, the check will ensure static constant names conform to the selected casing.

+

StaticConstantPrefix

+

When defined, the check will ensure static constant names will add the prefixed with the given value (regardless of casing).

+

StaticConstantIgnoredRegexp

+

Identifier naming checks won’t be enforced for static constant names matching this regular expression.

+

StaticConstantSuffix

+

When defined, the check will ensure static constant names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • StaticConstantCase of lower_case
  • +
  • StaticConstantPrefix of pre_
  • +
  • StaticConstantSuffix of _post
  • +
+

Identifies and/or transforms static constant names as follows:

+

Before:

+
static unsigned const MyConstStatic_array[] = {1, 2, 3};
+

After:

+
static unsigned const pre_myconststatic_array_post[] = {1, 2, 3};
+

StaticVariableCase

+

When defined, the check will ensure static variable names conform to the selected casing.

+

StaticVariablePrefix

+

When defined, the check will ensure static variable names will add the prefixed with the given value (regardless of casing).

+

StaticVariableIgnoredRegexp

+

Identifier naming checks won’t be enforced for static variable names matching this regular expression.

+

StaticVariableSuffix

+

When defined, the check will ensure static variable names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • StaticVariableCase of lower_case
  • +
  • StaticVariablePrefix of pre_
  • +
  • StaticVariableSuffix of _post
  • +
+

Identifies and/or transforms static variable names as follows:

+

Before:

+
static unsigned MyStatic_array[] = {1, 2, 3};
+

After:

+
static unsigned pre_mystatic_array_post[] = {1, 2, 3};
+

StructCase

+

When defined, the check will ensure struct names conform to the selected casing.

+

StructPrefix

+

When defined, the check will ensure struct names will add the prefixed with the given value (regardless of casing).

+

StructIgnoredRegexp

+

Identifier naming checks won’t be enforced for struct names matching this regular expression.

+

StructSuffix

+

When defined, the check will ensure struct names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • StructCase of lower_case
  • +
  • StructPrefix of pre_
  • +
  • StructSuffix of _post
  • +
+

Identifies and/or transforms struct names as follows:

+

Before:

+
struct FOO {
+  FOO();
+  ~FOO();
+};
+

After:

+
struct pre_foo_post {
+  pre_foo_post();
+  ~pre_foo_post();
+};
+

TemplateParameterCase

+

When defined, the check will ensure template parameter names conform to the selected casing.

+

TemplateParameterPrefix

+

When defined, the check will ensure template parameter names will add the prefixed with the given value (regardless of casing).

+

TemplateParameterIgnoredRegexp

+

Identifier naming checks won’t be enforced for template parameter names matching this regular expression.

+

TemplateParameterSuffix

+

When defined, the check will ensure template parameter names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • TemplateParameterCase of lower_case
  • +
  • TemplateParameterPrefix of pre_
  • +
  • TemplateParameterSuffix of _post
  • +
+

Identifies and/or transforms template parameter names as follows:

+

Before:

+
template <typename T> class Foo {};
+

After:

+
template <typename pre_t_post> class Foo {};
+

TemplateTemplateParameterCase

+

When defined, the check will ensure template template parameter names conform to the selected casing.

+

TemplateTemplateParameterPrefix

+

When defined, the check will ensure template template parameter names will add the prefixed with the given value (regardless of casing).

+

TemplateTemplateParameterIgnoredRegexp

+

Identifier naming checks won’t be enforced for template template parameter names matching this regular expression.

+

TemplateTemplateParameterSuffix

+

When defined, the check will ensure template template parameter names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • TemplateTemplateParameterCase of lower_case
  • +
  • TemplateTemplateParameterPrefix of pre_
  • +
  • TemplateTemplateParameterSuffix of _post
  • +
+

Identifies and/or transforms template template parameter names as follows:

+

Before:

+
template <template <typename> class TPL_parameter, int COUNT_params,
+          typename... TYPE_parameters>
+

After:

+
template <template <typename> class pre_tpl_parameter_post, int COUNT_params,
+          typename... TYPE_parameters>
+

TypeAliasCase

+

When defined, the check will ensure type alias names conform to the selected casing.

+

TypeAliasPrefix

+

When defined, the check will ensure type alias names will add the prefixed with the given value (regardless of casing).

+

TypeAliasIgnoredRegexp

+

Identifier naming checks won’t be enforced for type alias names matching this regular expression.

+

TypeAliasSuffix

+

When defined, the check will ensure type alias names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • TypeAliasCase of lower_case
  • +
  • TypeAliasPrefix of pre_
  • +
  • TypeAliasSuffix of _post
  • +
+

Identifies and/or transforms type alias names as follows:

+

Before:

+
using MY_STRUCT_TYPE = my_structure;
+

After:

+
using pre_my_struct_type_post = my_structure;
+

TypedefCase

+

When defined, the check will ensure typedef names conform to the selected casing.

+

TypedefPrefix

+

When defined, the check will ensure typedef names will add the prefixed with the given value (regardless of casing).

+

TypedefIgnoredRegexp

+

Identifier naming checks won’t be enforced for typedef names matching this regular expression.

+

TypedefSuffix

+

When defined, the check will ensure typedef names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • TypedefCase of lower_case
  • +
  • TypedefPrefix of pre_
  • +
  • TypedefSuffix of _post
  • +
+

Identifies and/or transforms typedef names as follows:

+

Before:

+
typedef int MYINT;
+

After:

+
typedef int pre_myint_post;
+

TypeTemplateParameterCase

+

When defined, the check will ensure type template parameter names conform to the selected casing.

+

TypeTemplateParameterPrefix

+

When defined, the check will ensure type template parameter names will add the prefixed with the given value (regardless of casing).

+

TypeTemplateParameterIgnoredRegexp

+

Identifier naming checks won’t be enforced for type template names matching this regular expression.

+

TypeTemplateParameterSuffix

+

When defined, the check will ensure type template parameter names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • TypeTemplateParameterCase of lower_case
  • +
  • TypeTemplateParameterPrefix of pre_
  • +
  • TypeTemplateParameterSuffix of _post
  • +
+

Identifies and/or transforms type template parameter names as follows:

+

Before:

+
template <template <typename> class TPL_parameter, int COUNT_params,
+          typename... TYPE_parameters>
+

After:

+
template <template <typename> class TPL_parameter, int COUNT_params,
+          typename... pre_type_parameters_post>
+

UnionCase

+

When defined, the check will ensure union names conform to the selected casing.

+

UnionPrefix

+

When defined, the check will ensure union names will add the prefixed with the given value (regardless of casing).

+

UnionIgnoredRegexp

+

Identifier naming checks won’t be enforced for union names matching this regular expression.

+

UnionSuffix

+

When defined, the check will ensure union names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • UnionCase of lower_case
  • +
  • UnionPrefix of pre_
  • +
  • UnionSuffix of _post
  • +
+

Identifies and/or transforms union names as follows:

+

Before:

+
union FOO {
+  int a;
+  char b;
+};
+

After:

+
union pre_foo_post {
+  int a;
+  char b;
+};
+

ValueTemplateParameterCase

+

When defined, the check will ensure value template parameter names conform to the selected casing.

+

ValueTemplateParameterPrefix

+

When defined, the check will ensure value template parameter names will add the prefixed with the given value (regardless of casing).

+

ValueTemplateParameterIgnoredRegexp

+

Identifier naming checks won’t be enforced for value template parameter names matching this regular expression.

+

ValueTemplateParameterSuffix

+

When defined, the check will ensure value template parameter names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • ValueTemplateParameterCase of lower_case
  • +
  • ValueTemplateParameterPrefix of pre_
  • +
  • ValueTemplateParameterSuffix of _post
  • +
+

Identifies and/or transforms value template parameter names as follows:

+

Before:

+
template <template <typename> class TPL_parameter, int COUNT_params,
+          typename... TYPE_parameters>
+

After:

+
template <template <typename> class TPL_parameter, int pre_count_params_post,
+          typename... TYPE_parameters>
+

VariableCase

+

When defined, the check will ensure variable names conform to the selected casing.

+

VariablePrefix

+

When defined, the check will ensure variable names will add the prefixed with the given value (regardless of casing).

+

VariableIgnoredRegexp

+

Identifier naming checks won’t be enforced for variable names matching this regular expression.

+

VariableSuffix

+

When defined, the check will ensure variable names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • VariableCase of lower_case
  • +
  • VariablePrefix of pre_
  • +
  • VariableSuffix of _post
  • +
+

Identifies and/or transforms variable names as follows:

+

Before:

+
unsigned MyVariable;
+

After:

+
unsigned pre_myvariable_post;
+

VirtualMethodCase

+

When defined, the check will ensure virtual method names conform to the selected casing.

+

VirtualMethodPrefix

+

When defined, the check will ensure virtual method names will add the prefixed with the given value (regardless of casing).

+

VirtualMethodIgnoredRegexp

+

Identifier naming checks won’t be enforced for virtual method names matching this regular expression.

+

VirtualMethodSuffix

+

When defined, the check will ensure virtual method names will add the suffix with the given value (regardless of casing).

+

For example using values of:

+
    +
  • VirtualMethodCase of lower_case
  • +
  • VirtualMethodPrefix of pre_
  • +
  • VirtualMethodSuffix of _post
  • +
+

Identifies and/or transforms virtual method names as follows:

+

Before:

+
class Foo {
+public:
+  virtual int MemberFunction();
+}
+

After:

+
class Foo {
+public:
+  virtual int pre_member_function_post();
+}
+

(Clang-Tidy original name: readability-identifier-naming)

+ + +#### Implicit Bool Conversion {#CT_RDB_IBC} +

This check can be used to find implicit conversions between built-in types and booleans. Depending on use case, it may simply help with readability of the code, or in some cases, point to potential bugs which remain unnoticed due to implicit conversions.

+

The following is a real-world example of bug which was hiding behind implicit bool conversion:

+
class Foo {
+  int m_foo;
+
+public:
+  void setFoo(bool foo) { m_foo = foo; } // warning: implicit conversion bool -> int
+  int getFoo() { return m_foo; }
+};
+
+void use(Foo& foo) {
+  bool value = foo.getFoo(); // warning: implicit conversion int -> bool
+}
+

This code is the result of unsuccessful refactoring, where type of m_foo changed from bool to int. The programmer forgot to change all occurrences of bool, and the remaining code is no longer correct, yet it still compiles without any visible warnings.

+

In addition to issuing warnings, fix-it hints are provided to help solve the reported issues. This can be used for improving readability of code, for example:

+
void conversionsToBool() {
+  float floating;
+  bool boolean = floating;
+  // ^ propose replacement: bool boolean = floating != 0.0f;
+
+  int integer;
+  if (integer) {}
+  // ^ propose replacement: if (integer != 0) {}
+
+  int* pointer;
+  if (!pointer) {}
+  // ^ propose replacement: if (pointer == nullptr) {}
+
+  while (1) {}
+  // ^ propose replacement: while (true) {}
+}
+
+void functionTakingInt(int param);
+
+void conversionsFromBool() {
+  bool boolean;
+  functionTakingInt(boolean);
+  // ^ propose replacement: functionTakingInt(static_cast<int>(boolean));
+
+  functionTakingInt(true);
+  // ^ propose replacement: functionTakingInt(1);
+}
+

In general, the following conversion types are checked:

+
    +
  • integer expression/literal to boolean (conversion from a single bit bitfield to boolean is explicitly allowed, since there’s no ambiguity / information loss in this case),
  • +
  • floating expression/literal to boolean,
  • +
  • pointer/pointer to member/nullptr/NULL to boolean,
  • +
  • boolean expression/literal to integer (conversion from boolean to a single bit bitfield is explicitly allowed),
  • +
  • boolean expression/literal to floating.
  • +
+

The rules for generating fix-it hints are:

+
    +
  • in case of conversions from other built-in type to bool, an explicit comparison is proposed to make it clear what exactly is being compared: +
      +
    • bool boolean = floating; is changed to bool boolean = floating == 0.0f;,
    • +
    • for other types, appropriate literals are used (0, 0u, 0.0f, 0.0, nullptr),
    • +
  • +
  • in case of negated expressions conversion to bool, the proposed replacement with comparison is simplified: +
      +
    • if (!pointer) is changed to if (pointer == nullptr),
    • +
  • +
  • in case of conversions from bool to other built-in types, an explicit static_cast is proposed to make it clear that a conversion is taking place: +
      +
    • int integer = boolean; is changed to int integer = static_cast(boolean);,
    • +
  • +
  • if the conversion is performed on type literals, an equivalent literal is proposed, according to what type is actually expected, for example: +
      +
    • functionTakingBool(0); is changed to functionTakingBool(false);,
    • +
    • functionTakingInt(true); is changed to functionTakingInt(1);,
    • +
    • for other types, appropriate literals are used (false, true, 0, 1, 0u, 1u, 0.0f, 1.0f, 0.0, 1.0f).
    • +
  • +
+

Some additional accommodations are made for pre-C++11 dialects:

+
    +
  • false literal conversion to pointer is detected,
  • +
  • instead of nullptr literal, 0 is proposed as replacement.
  • +
+

Occurrences of implicit conversions inside macros and template instantiations are deliberately ignored, as it is not clear how to deal with such cases.

+
Options
+

AllowIntegerConditions

+

When true, the check will allow conditional integer conversions. Default is false.

+

AllowPointerConditions

+

When true, the check will allow conditional pointer conversions. Default is false.

+

(Clang-Tidy original name: readability-implicit-bool-conversion)

+ + +#### Inconsistent Declaration Parameter Name {#CT_RDB_IDPN} +

Find function declarations which differ in parameter names.

+

Example:

+
// in foo.hpp:
+void foo(int a, int b, int c);
+
+// in foo.cpp:
+void foo(int d, int e, int f); // warning
+

This check should help to enforce consistency in large projects, where it often happens that a definition of function is refactored, changing the parameter names, but its declaration in header file is not updated. With this check, we can easily find and correct such inconsistencies, keeping declaration and definition always in sync.

+

Unnamed parameters are allowed and are not taken into account when comparing function declarations, for example:

+
void foo(int a);
+void foo(int); // no warning
+

One name is also allowed to be a case-insensitive prefix/suffix of the other:

+
void foo(int count);
+void foo(int count_input) { // no warning
+  int count = adjustCount(count_input);
+}
+

To help with refactoring, in some cases fix-it hints are generated to align parameter names to a single naming convention. This works with the assumption that the function definition is the most up-to-date version, as it directly references parameter names in its body. Example:

+
void foo(int a); // warning and fix-it hint (replace "a" to "b")
+int foo(int b) { return b + 2; } // definition with use of "b"
+

In the case of multiple redeclarations or function template specializations, a warning is issued for every redeclaration or specialization inconsistent with the definition or the first declaration seen in a translation unit.

+

IgnoreMacros

+

If this option is set to true (default is true), the check will not warn about names declared inside macros.

+

Strict

+

If this option is set to true (default is false), then names must match exactly (or be absent).

+

(Clang-Tidy original name: readability-inconsistent-declaration-parameter-name)

+ + +#### Isolate Declaration {#CT_RDB_ID} +

Detects local variable declarations declaring more than one variable and tries to refactor the code to one statement per declaration.

+

The automatic code-transformation will use the same indentation as the original for every created statement and add a line break after each statement. It keeps the order of the variable declarations consistent, too.

+
void f() {
+  int * pointer = nullptr, value = 42, * const const_ptr = &value;
+  // This declaration will be diagnosed and transformed into:
+  // int * pointer = nullptr;
+  // int value = 42;
+  // int * const const_ptr = &value;
+}
+

The check excludes places where it is necessary or common to declare multiple variables in one statement and there is no other way supported in the language. Please note that structured bindings are not considered.

+
// It is not possible to transform this declaration and doing the declaration
+// before the loop will increase the scope of the variable 'Begin' and 'End'
+// which is undesirable.
+for (int Begin = 0, End = 100; Begin < End; ++Begin);
+if (int Begin = 42, Result = some_function(Begin); Begin == Result);
+
+// It is not possible to transform this declaration because the result is
+// not functionality preserving as 'j' and 'k' would not be part of the
+// 'if' statement anymore.
+if (SomeCondition())
+  int i = 42, j = 43, k = function(i,j);
+
Limitations
+

Global variables and member variables are excluded.

+

The check currently does not support the automatic transformation of member-pointer-types.

+
struct S {
+  int a;
+  const int b;
+  void f() {}
+};
+
+void f() {
+  // Only a diagnostic message is emitted
+  int S::*p = &S::a, S::*const q = &S::a;
+}
+

Furthermore, the transformation is very cautious when it detects various kinds of macros or preprocessor directives in the range of the statement. In this case the transformation will not happen to avoid unexpected side-effects due to macros.

+
#define NULL 0
+#define MY_NICE_TYPE int **
+#define VAR_NAME(name) name##__LINE__
+#define A_BUNCH_OF_VARIABLES int m1 = 42, m2 = 43, m3 = 44;
+
+void macros() {
+  int *p1 = NULL, *p2 = NULL;
+  // Will be transformed to
+  // int *p1 = NULL;
+  // int *p2 = NULL;
+
+  MY_NICE_TYPE p3, v1, v2;
+  // Won't be transformed, but a diagnostic is emitted.
+
+  int VAR_NAME(v3),
+      VAR_NAME(v4),
+      VAR_NAME(v5);
+  // Won't be transformed, but a diagnostic is emitted.
+
+  A_BUNCH_OF_VARIABLES
+  // Won't be transformed, but a diagnostic is emitted.
+
+  int Unconditional,
+#if CONFIGURATION
+      IfConfigured = 42,
+#else
+      IfConfigured = 0;
+#endif
+  // Won't be transformed, but a diagnostic is emitted.
+}
+

(Clang-Tidy original name: readability-isolate-declaration)

+ + +#### Magic Numbers {#CT_RDB_MN} +

Detects magic numbers, integer or floating point literals that are embedded in code and not introduced via constants or symbols.

+

Many coding guidelines advise replacing the magic values with symbolic constants to improve readability. Here are a few references:

+ +

Examples of magic values:

+
double circleArea = 3.1415926535 * radius * radius;
+
+double totalCharge = 1.08 * itemPrice;
+
+int getAnswer() {
+   return -3; // FILENOTFOUND
+}
+
+for (int mm = 1; mm <= 12; ++mm) {
+   std::cout << month[mm] << '\n';
+}
+

Example with magic values refactored:

+
double circleArea = M_PI * radius * radius;
+
+const double TAX_RATE = 0.08;  // or make it variable and read from a file
+
+double totalCharge = (1.0 + TAX_RATE) * itemPrice;
+
+int getAnswer() {
+   return E_FILE_NOT_FOUND;
+}
+
+for (int mm = 1; mm <= MONTHS_IN_A_YEAR; ++mm) {
+   std::cout << month[mm] << '\n';
+}
+

For integral literals by default only 0 and 1 (and -1) integer values are accepted without a warning. This can be overridden with the IgnoredIntegerValues option. Negative values are accepted if their absolute value is present in the IgnoredIntegerValues list.

+

As a special case for integral values, all powers of two can be accepted without warning by enabling the IgnorePowersOf2IntegerValues option.

+

For floating point literals by default the 0.0 floating point value is accepted without a warning. The set of ignored floating point literals can be configured using the IgnoredFloatingPointValues option. For each value in that set, the given string value is converted to a floating-point value representation used by the target architecture. If a floating-point literal value compares equal to one of the converted values, then that literal is not diagnosed by this check. Because floating-point equality is used to determine whether to diagnose or not, the user needs to be aware of the details of floating-point representations for any values that cannot be precisely represented for their target architecture.

+

For each value in the IgnoredFloatingPointValues set, both the single-precision form and double-precision form are accepted (for example, if 3.14 is in the set, neither 3.14f nor 3.14 will produce a warning).

+

Scientific notation is supported for both source code input and option. Alternatively, the check for the floating point numbers can be disabled for all floating point values by enabling the IgnoreAllFloatingPointValues option.

+

Since values 0 and 0.0 are so common as the base counter of loops, or initialization values for sums, they are always accepted without warning, even if not present in the respective ignored values list.

+
Options
+

IgnoredIntegerValues

+

Semicolon-separated list of magic positive integers that will be accepted without a warning. Default values are {1, 2, 3, 4}, and 0 is accepted unconditionally.

+

IgnorePowersOf2IntegerValues

+

Boolean value indicating whether to accept all powers-of-two integer values without warning. Default value is false.

+

IgnoredFloatingPointValues

+

Semicolon-separated list of magic positive floating point values that will be accepted without a warning. Default values are {1.0, 100.0} and 0.0 is accepted unconditionally.

+

IgnoreAllFloatingPointValues

+

Boolean value indicating whether to accept all floating point values without warning. Default value is false.

+

IgnoreBitFieldsWidths

+

Boolean value indicating whether to accept magic numbers as bit field widths without warning. This is useful for example for register definitions which are generated from hardware specifications. Default value is true.

+

(Clang-Tidy original name: readability-magic-numbers)

+ + +#### Make Member Function Const {#CT_RDB_MMFC} +

Finds non-static member functions that can be made const because the functions don’t use this in a non-const way.

+

This check tries to annotate methods according to logical constness (not physical constness). Therefore, it will suggest to add a const qualifier to a non-const method only if this method does something that is already possible though the public interface on a const pointer to the object:

+
    +
  • reading a public member variable
  • +
  • calling a public const-qualified member function
  • +
  • returning const-qualified this
  • +
  • passing const-qualified this as a parameter.
  • +
+

This check will also suggest to add a const qualifier to a non-const method if this method uses private data and functions in a limited number of ways where logical constness and physical constness coincide:

+
    +
  • reading a member variable of builtin type
  • +
+

Specifically, this check will not suggest to add a const to a non-const method if the method reads a private member variable of pointer type because that allows to modify the pointee which might not preserve logical constness. For the same reason, it does not allow to call private member functions or member functions on private member variables.

+

In addition, this check ignores functions that

+ +

The following real-world examples will be preserved by the check:

+
class E1 {
+  Pimpl &getPimpl() const;
+public:
+  int &get() {
+    // Calling a private member function disables this check.
+    return getPimpl()->i;
+  }
+  ...
+};
+
+class E2 {
+public:
+  const int *get() const;
+  // const_cast disables this check.
+  S *get() {
+    return const_cast<int*>(const_cast<const C*>(this)->get());
+  }
+  ...
+};
+

After applying modifications as suggested by the check, running the check again might find more opportunities to mark member functions const.

+

(Clang-Tidy original name: readability-make-member-function-const)

+ + +#### Misleading Indentation {#CT_RDB_MI} +

Correct indentation helps to understand code. Mismatch of the syntactical structure and the indentation of the code may hide serious problems. Missing braces can also make it significantly harder to read the code, therefore it is important to use braces.

+

The way to avoid dangling else is to always check that an else belongs to the if that begins in the same column.

+

You can omit braces when your inner part of e.g. an if statement has only one statement in it. Although in that case you should begin the next statement in the same column with the if.

+

Examples:

+
// Dangling else:
+if (cond1)
+  if (cond2)
+    foo1();
+else
+  foo2();  // Wrong indentation: else belongs to if(cond2) statement.
+
+// Missing braces:
+if (cond1)
+  foo1();
+  foo2();  // Not guarded by if(cond1).
+
Limitations
+

Note that this check only works as expected when the tabs or spaces are used consistently and not mixed.

+

(Clang-Tidy original name: readability-misleading-indentation)

+ + +#### Misplaced Array Index {#CT_RDB_MAI} +

This check warns for unusual array index syntax.

+

The following code has unusual array index syntax:

+
void f(int *X, int Y) {
+  Y[X] = 0;
+}
+

becomes

+
void f(int *X, int Y) {
+  X[Y] = 0;
+}
+

The check warns about such unusual syntax for readability reasons:

+
    +
  • There are programmers that are not familiar with this unusual syntax.
  • +
  • It is possible that variables are mixed up.
  • +
+

(Clang-Tidy original name: readability-misplaced-array-index)

+ + +#### Named Parameter {#CT_RDB_NP} +

Find functions with unnamed arguments.

+

The check implements the following rule originating in the Google C++ Style Guide:

+

https://google.github.io/styleguide/cppguide.html\#Function_Declarations_and_Definitions

+

All parameters should be named, with identical names in the declaration and implementation.

+

Corresponding cpplint.py check name: readability/function.

+

(Clang-Tidy original name: readability-named-parameter)

+ + +#### Non Const Parameter {#CT_RDB_NCP} +

The check finds function parameters of a pointer type that could be changed to point to a constant type instead.

+

When const is used properly, many mistakes can be avoided. Advantages when using const properly:

+
    +
  • prevent unintentional modification of data;
  • +
  • get additional warnings such as using uninitialized data;
  • +
  • make it easier for developers to see possible side effects.
  • +
+

This check is not strict about constness, it only warns when the constness will make the function interface safer.

+
// warning here; the declaration "const char *p" would make the function
+// interface safer.
+char f1(char *p) {
+  return *p;
+}
+
+// no warning; the declaration could be more const "const int * const p" but
+// that does not make the function interface safer.
+int f2(const int *p) {
+  return *p;
+}
+
+// no warning; making x const does not make the function interface safer
+int f3(int x) {
+  return x;
+}
+
+// no warning; Technically, *p can be const ("const struct S *p"). But making
+// *p const could be misleading. People might think that it's safe to pass
+// const data to this function.
+struct S { int *a; int *b; };
+int f3(struct S *p) {
+  *(p->a) = 0;
+}
+

(Clang-Tidy original name: readability-non-const-parameter)

+ + +#### Qualified Auto {#CT_RDB_QA} +

Adds pointer qualifications to auto-typed variables that are deduced to pointers.

+

LLVM Coding Standards advises to make it obvious if a auto typed variable is a pointer. This check will transform auto to auto * when the type is deduced to be a pointer.

+
for (auto Data : MutatablePtrContainer) {
+  change(*Data);
+}
+for (auto Data : ConstantPtrContainer) {
+  observe(*Data);
+}
+

Would be transformed into:

+
for (auto *Data : MutatablePtrContainer) {
+  change(*Data);
+}
+for (const auto *Data : ConstantPtrContainer) {
+  observe(*Data);
+}
+

Note const volatile qualified types will retain their const and volatile qualifiers. Pointers to pointers will not be fully qualified.

+
const auto Foo = cast<int *>(Baz1);
+const auto Bar = cast<const int *>(Baz2);
+volatile auto FooBar = cast<int *>(Baz3);
+auto BarFoo = cast<int **>(Baz4);
+

Would be transformed into:

+
auto *const Foo = cast<int *>(Baz1);
+const auto *const Bar = cast<const int *>(Baz2);
+auto *volatile FooBar = cast<int *>(Baz3);
+auto *BarFoo = cast<int **>(Baz4);
+
Options
+

AddConstToQualified

+

When set to true the check will add const qualifiers variables defined as auto * or auto & when applicable. Default value is true.

+
auto Foo1 = cast<const int *>(Bar1);
+auto *Foo2 = cast<const int *>(Bar2);
+auto &Foo3 = cast<const int &>(Bar3);
+

If AddConstToQualified is set to false, it will be transformed into:

+
const auto *Foo1 = cast<const int *>(Bar1);
+auto *Foo2 = cast<const int *>(Bar2);
+auto &Foo3 = cast<const int &>(Bar3);
+

Otherwise it will be transformed into:

+
const auto *Foo1 = cast<const int *>(Bar1);
+const auto *Foo2 = cast<const int *>(Bar2);
+const auto &Foo3 = cast<const int &>(Bar3);
+

Note in the LLVM alias, the default value is false.

+

(Clang-Tidy original name: readability-qualified-auto)

+ + +#### Redundant Access Specifiers {#CT_RDB_RAS} +

Finds classes, structs, and unions containing redundant member (field and method) access specifiers.

+
Example
+
class Foo {
+public:
+  int x;
+  int y;
+public:
+  int z;
+protected:
+  int a;
+public:
+  int c;
+}
+

In the example above, the second public declaration can be removed without any changes of behavior.

+
Options
+

CheckFirstDeclaration

+

If set to true, the check will also diagnose if the first access specifier declaration is redundant (e.g. private inside class, or public inside struct or union). Default is false.

+
Example
+
struct Bar {
+public:
+  int x;
+}
+

If CheckFirstDeclaration option is enabled, a warning about redundant access specifier will be emitted, because public is the default member access for structs.

+

(Clang-Tidy original name: readability-redundant-access-specifiers)

+ + +#### Redundant Control Flow {#CT_RDB_RCF} +

This check looks for procedures (functions returning no value) with return statements at the end of the function. Such return statements are redundant.

+

Loop statements (for, while, do while) are checked for redundant continue statements at the end of the loop body.

+

Examples:

+

The following function f contains a redundant return statement:

+
extern void g();
+void f() {
+  g();
+  return;
+}
+

becomes

+
extern void g();
+void f() {
+  g();
+}
+

The following function k contains a redundant continue statement:

+
void k() {
+  for (int i = 0; i < 10; ++i) {
+    continue;
+  }
+}
+

becomes

+
void k() {
+  for (int i = 0; i < 10; ++i) {
+  }
+}
+

(Clang-Tidy original name: readability-redundant-control-flow)

+ + +#### Redundant Declaration {#CT_RDB_RD} +

Finds redundant variable and function declarations.

+
extern int X;
+extern int X;
+

becomes

+
extern int X;
+

Such redundant declarations can be removed without changing program behaviour. They can for instance be unintentional left overs from previous refactorings when code has been moved around. Having redundant declarations could in worst case mean that there are typos in the code that cause bugs.

+

Normally the code can be automatically fixed, clang-tidy can remove the second declaration. However there are 2 cases when you need to fix the code manually:

+
    +
  • When the declarations are in different header files;
  • +
  • When multiple variables are declared together.
  • +
+
Options
+

IgnoreMacros

+

If set to true, the check will not give warnings inside macros. Default is true.

+

(Clang-Tidy original name: readability-redundant-declaration)

+ + +#### Redundant Function Ptr Dereference {#CT_RDB_RFPD} +

Finds redundant dereferences of a function pointer.

+

Before:

+
int f(int,int);
+int (*p)(int, int) = &f;
+
+int i = (**p)(10, 50);
+

After:

+
int f(int,int);
+int (*p)(int, int) = &f;
+
+int i = (*p)(10, 50);
+

(Clang-Tidy original name: readability-redundant-function-ptr-dereference)

+ + +#### Redundant Member Init {#CT_RDB_RMI} +

Finds member initializations that are unnecessary because the same default constructor would be called if they were not present.

+
Example
+
// Explicitly initializing the member s is unnecessary.
+class Foo {
+public:
+  Foo() : s() {}
+
+private:
+  std::string s;
+};
+
Options
+

IgnoreBaseInCopyConstructors

+

Default is false.

+

When true, the check will ignore unnecessary base class initializations within copy constructors, since some compilers issue warnings/errors when base classes are not explicitly intialized in copy constructors. For example, gcc with -Wextra or -Werror=extra issues warning or error base class 'Bar' should be explicitly initialized in the copy constructor if Bar() were removed in the following example:

+
// Explicitly initializing member s and base class Bar is unnecessary.
+struct Foo : public Bar {
+  // Remove s() below. If IgnoreBaseInCopyConstructors!=0, keep Bar().
+  Foo(const Foo& foo) : Bar(), s() {}
+  std::string s;
+};
+

(Clang-Tidy original name: readability-redundant-member-init)

+ + +#### Redundant Preprocessor {#CT_RDB_RP} +

Finds potentially redundant preprocessor directives. At the moment the following cases are detected:

+
    +
  • #ifdef .. #endif pairs which are nested inside an outer pair with the same condition. For example:
  • +
+
#ifdef FOO
+#ifdef FOO // inner ifdef is considered redundant
+void f();
+#endif
+#endif
+
    +
  • Same for #ifndef .. #endif pairs. For example:
  • +
+
#ifndef FOO
+#ifndef FOO // inner ifndef is considered redundant
+void f();
+#endif
+#endif
+
    +
  • #ifndef inside an #ifdef with the same condition:
  • +
+
#ifdef FOO
+#ifndef FOO // inner ifndef is considered redundant
+void f();
+#endif
+#endif
+
    +
  • #ifdef inside an #ifndef with the same condition:
  • +
+
#ifndef FOO
+#ifdef FOO // inner ifdef is considered redundant
+void f();
+#endif
+#endif
+
    +
  • #if .. #endif pairs which are nested inside an outer pair with the same condition. For example:
  • +
+
#define FOO 4
+#if FOO == 4
+#if FOO == 4 // inner if is considered redundant
+void f();
+#endif
+#endif
+

(Clang-Tidy original name: readability-redundant-preprocessor)

+ + +#### Redundant Smartptr Get {#CT_RDB_RSG} +

Find and remove redundant calls to smart pointer’s .get() method.

+

Examples:

+
ptr.get()->Foo()  ==>  ptr->Foo()
+*ptr.get()  ==>  *ptr
+*ptr->get()  ==>  **ptr
+if (ptr.get() == nullptr) ... => if (ptr == nullptr) ...
+

IgnoreMacros

+

If this option is set to true (default is true), the check will not warn about calls inside macros.

+

(Clang-Tidy original name: readability-redundant-smartptr-get)

+ + +#### Redundant String Cstr {#CT_RDB_RSC} +

Finds unnecessary calls to std::string::c_str() and std::string::data().

+

(Clang-Tidy original name: readability-redundant-string-cstr)

+ + +#### Redundant String Init {#CT_RDB_RSI} +

Finds unnecessary string initializations.

+
Examples
+
// Initializing string with empty string literal is unnecessary.
+std::string a = "";
+std::string b("");
+
+// becomes
+
+std::string a;
+std::string b;
+
+// Initializing a string_view with an empty string literal produces an
+// instance that compares equal to string_view().
+std::string_view a = "";
+std::string_view b("");
+
+// becomes
+std::string_view a;
+std::string_view b;
+
Options
+

StringNames

+

Default is ::std::basic_string;::std::basic_string_view.

+

Semicolon-delimited list of class names to apply this check to. By default ::std::basic_string applies to std::string and std::wstring. Set to e.g. ::std::basic_string;llvm::StringRef;QString to perform this check on custom classes.

+

(Clang-Tidy original name: readability-redundant-string-init)

+ + +#### Simplify Boolean Expr {#CT_RDB_SBE} +

Looks for boolean expressions involving boolean constants and simplifies them to use the appropriate boolean expression directly.

+

Examples:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Initial expressionResult
if (b == true)if (b)
if (b == false)if (!b)
if (b && true)if (b)
if (b && false)if (false)
if (b
if (b
e ? true : falsee
e ? false : true!e
if (true) t(); else f();t();
if (false) t(); else f();f();
if (e) return true; else return false;return e;
if (e) return false; else return true;return !e;
if (e) b = true; else b = false;b = e;
if (e) b = false; else b = true;b = !e;
if (e) return true; return false;return e;
if (e) return false; return true;return !e;
+

The resulting expression e is modified as follows:

+
    +
  1. Unnecessary parentheses around the expression are removed.
  2. +
  3. Negated applications of ! are eliminated.
  4. +
  5. Negated applications of comparison operators are changed to use the opposite condition.
  6. +
  7. Implicit conversions of pointers, including pointers to members, to bool are replaced with explicit comparisons to nullptr in C++11 or NULL in C++98/03.
  8. +
  9. Implicit casts to bool are replaced with explicit casts to bool.
  10. +
  11. Object expressions with explicit operator bool conversion operators are replaced with explicit casts to bool.
  12. +
  13. Implicit conversions of integral types to bool are replaced with explicit comparisons to 0.
  14. +
+

Examples:

+
    +
  1. The ternary assignment bool b = (i < 0) ? true : false; has redundant parentheses and becomes bool b = i < 0;.

  2. +
  3. The conditional return if (!b) return false; return true; has an implied double negation and becomes return b;.

  4. +
  5. The conditional return if (i < 0) return false; return true; becomes return i >= 0;.

  6. +
+

The conditional return if (i != 0) return false; return true; becomes return i == 0;.

+
    +
  1. The conditional return if (p) return true; return false; has an implicit conversion of a pointer to bool and becomes return p != nullptr;.
  2. +
+

The ternary assignment bool b = (i & 1) ? true : false; has an implicit conversion of i & 1 to bool and becomes bool b = (i & 1) != 0;.

+
    +
  1. The conditional return if (i & 1) return true; else return false; has an implicit conversion of an integer quantity i & 1 to bool and becomes return (i & 1) != 0;

  2. +
  3. Given struct X { explicit operator bool(); };, and an instance x of struct X, the conditional return if (x) return true; return false; becomes return static_cast(x);

  4. +
+
Options
+

ChainedConditionalReturn

+

If true, conditional boolean return statements at the end of an if/else if chain will be transformed. Default is false.

+

ChainedConditionalAssignment

+

If true, conditional boolean assignments at the end of an if/else if chain will be transformed. Default is false.

+

(Clang-Tidy original name: readability-simplify-boolean-expr)

+ + +#### Simplify Subscript Expr {#CT_RDB_SSE} +

This check simplifies subscript expressions. Currently this covers calling .data() and immediately doing an array subscript operation to obtain a single element, in which case simply calling operator[] suffice.

+

Examples:

+
std::string s = ...;
+char c = s.data()[i];  // char c = s[i];
+
Options
+

Types

+

The list of type(s) that triggers this check. Default is ::std::basic_string;::std::basic_string_view;::std::vector;::std::array

+

(Clang-Tidy original name: readability-simplify-subscript-expr)

+ + +#### Static Accessed Through Instance {#CT_RDB_SATI} +

Checks for member expressions that access static members through instances, and replaces them with uses of the appropriate qualified-id.

+

Example:

+

The following code:

+
struct C {
+  static void foo();
+  static int x;
+};
+
+C *c1 = new C();
+c1->foo();
+c1->x;
+

is changed to:

+
C *c1 = new C();
+C::foo();
+C::x;
+

(Clang-Tidy original name: readability-static-accessed-through-instance)

+ + +#### Static Definition In Anonymous Namespace {#CT_RDB_SDIAN} +

Finds static function and variable definitions in anonymous namespace.

+

In this case, static is redundant, because anonymous namespace limits the visibility of definitions to a single translation unit.

+
namespace {
+  static int a = 1; // Warning.
+  static const b = 1; // Warning.
+}
+

The check will apply a fix by removing the redundant static qualifier.

+

(Clang-Tidy original name: readability-static-definition-in-anonymous-namespace)

+ + +#### String Compare {#CT_RDB_SC} +

Finds string comparisons using the compare method.

+

A common mistake is to use the string’s compare method instead of using the equality or inequality operators. The compare method is intended for sorting functions and thus returns a negative number, a positive number or zero depending on the lexicographical relationship between the strings compared. If an equality or inequality check can suffice, that is recommended. This is recommended to avoid the risk of incorrect interpretation of the return value and to simplify the code. The string equality and inequality operators can also be faster than the compare method due to early termination.

+

Examples:

+
std::string str1{"a"};
+std::string str2{"b"};
+
+// use str1 != str2 instead.
+if (str1.compare(str2)) {
+}
+
+// use str1 == str2 instead.
+if (!str1.compare(str2)) {
+}
+
+// use str1 == str2 instead.
+if (str1.compare(str2) == 0) {
+}
+
+// use str1 != str2 instead.
+if (str1.compare(str2) != 0) {
+}
+
+// use str1 == str2 instead.
+if (0 == str1.compare(str2)) {
+}
+
+// use str1 != str2 instead.
+if (0 != str1.compare(str2)) {
+}
+
+// Use str1 == "foo" instead.
+if (str1.compare("foo") == 0) {
+}
+

The above code examples shows the list of if-statements that this check will give a warning for. All of them uses compare to check if equality or inequality of two strings instead of using the correct operators.

+

(Clang-Tidy original name: readability-string-compare)

+ + +#### Uniqueptr Delete Release {#CT_RDB_UDR} +

Replace delete .release() with = nullptr. The latter is shorter, simpler and does not require use of raw pointer APIs.

+
std::unique_ptr<int> P;
+delete P.release();
+
+// becomes
+
+std::unique_ptr<int> P;
+P = nullptr;
+

(Clang-Tidy original name: readability-uniqueptr-delete-release)

+ + +#### Uppercase Literal Suffix {#CT_RDB_ULS} +

cert-dcl16-c redirects here as an alias for this check. By default, only the suffixes that begin with l (l, ll, lu, llu, but not u, ul, ull) are diagnosed by that alias.

+

hicpp-uppercase-literal-suffix redirects here as an alias for this check.

+

Detects when the integral literal or floating point (decimal or hexadecimal) literal has a non-uppercase suffix and provides a fix-it hint with the uppercase suffix.

+

All valid combinations of suffixes are supported.

+
auto x = 1;  // OK, no suffix.
+
+auto x = 1u; // warning: integer literal suffix 'u' is not upper-case
+
+auto x = 1U; // OK, suffix is uppercase.
+
+...
+
Options
+

NewSuffixes

+

Optionally, a list of the destination suffixes can be provided. When the suffix is found, a case-insensitive lookup in that list is made, and if a replacement is found that is different from the current suffix, then the diagnostic is issued. This allows for fine-grained control of what suffixes to consider and what their replacements should be.

+
Example
+

Given a list L;uL:

+
    +
  • l -> L
  • +
  • L will be kept as is.
  • +
  • ul -> uL
  • +
  • Ul -> uL
  • +
  • UL -> uL
  • +
  • uL will be kept as is.
  • +
  • ull will be kept as is, since it is not in the list
  • +
  • and so on.
  • +
+

IgnoreMacros

+

If this option is set to true (default is true), the check will not warn about literal suffixes inside macros.

+

(Clang-Tidy original name: readability-uppercase-literal-suffix)

+ + +#### Use Anyofallof {#CT_RDB_UA} +

Finds range-based for loops that can be replaced by a call to std::any_of or std::all_of. In C++ 20 mode, suggests std::ranges::any_of or std::ranges::all_of.

+

Example:

+
bool all_even(std::vector<int> V) {
+  for (int I : V) {
+    if (I % 2)
+      return false;
+  }
+  return true;
+  // Replace loop by
+  // return std::ranges::all_of(V, [](int I) { return I % 2 == 0; });
+}
+

(Clang-Tidy original name: readability-use-anyofallof)

+ + +### Static Analyzer - C++ + +#### Inner Pointer {#CT_SA_CPP_IP} +

Check for inner pointers of C++ containers used after re/deallocation.

+

Many container methods in the C++ standard library are known to invalidate “references” (including actual references, iterators and raw pointers) to elements of the container. Using such references after they are invalidated causes undefined behavior, which is a common source of memory errors in C++ that this checker is capable of finding.

+

The checker is currently limited to std::string objects and doesn’t recognize some of the more sophisticated approaches to passing unowned pointers around, such as std::string_view.

+
void deref_after_assignment() {
+  std::string s = "llvm";
+  const char *c = s.data(); // note: pointer to inner buffer of 'std::string' obtained here
+  s = "clang"; // note: inner buffer of 'std::string' reallocated by call to 'operator='
+  consume(c); // warn: inner pointer of container used after re/deallocation
+}
+
+const char *return_temp(int x) {
+  return std::to_string(x).c_str(); // warn: inner pointer of container used after re/deallocation
+  // note: pointer to inner buffer of 'std::string' obtained here
+  // note: inner buffer of 'std::string' deallocated by call to destructor
+}
+

(Clang-Tidy original name: clang-analyzer-cplusplus.InnerPointer)

+ + +#### Move {#CT_SA_CPP_M} +No documentation is available. + +#### New Delete {#CT_SA_CPP_ND} +

Check for double-free and use-after-free problems. Traces memory managed by new/delete.

+
void f(int *p);
+
+void testUseMiddleArgAfterDelete(int *p) {
+  delete p;
+  f(p); // warn: use after free
+}
+
+class SomeClass {
+public:
+  void f();
+};
+
+void test() {
+  SomeClass *c = new SomeClass;
+  delete c;
+  c->f(); // warn: use after free
+}
+
+void test() {
+  int *p = (int *)__builtin_alloca(sizeof(int));
+  delete p; // warn: deleting memory allocated by alloca
+}
+
+void test() {
+  int *p = new int;
+  delete p;
+  delete p; // warn: attempt to free released
+}
+
+void test() {
+  int i;
+  delete &i; // warn: delete address of local
+}
+
+void test() {
+  int *p = new int[1];
+  delete[] (++p);
+    // warn: argument to 'delete[]' is offset by 4 bytes
+    // from the start of memory allocated by 'new[]'
+}
+

(Clang-Tidy original name: clang-analyzer-cplusplus.NewDelete)

+ + +#### New Delete Leaks {#CT_SA_CPP_NDL} +

Check for memory leaks. Traces memory managed by new/delete.

+
void test() {
+  int *p = new int;
+} // warn
+

(Clang-Tidy original name: clang-analyzer-cplusplus.NewDeleteLeaks)

+ + +#### Placement New Checker {#CT_SA_CPP_PNC} +

Check if default placement new is provided with pointers to sufficient storage capacity.

+
#include <new>
+
+void f() {
+  short s;
+  long *lp = ::new (&s) long; // warn
+}
+

(Clang-Tidy original name: clang-analyzer-cplusplus.PlacementNew)

+ + +#### Pure Virtual Call {#CT_SA_CPP_PVC} +No documentation is available. + +#### Self Assignment {#CT_SA_CPP_SA} +

Checks C++ copy and move assignment operators for self assignment.

+

(Clang-Tidy original name: clang-analyzer-cplusplus.SelfAssignment)

+ + +### Static Analyzer - Core + +#### Call And Message {#CT_SA_COR_CAM} +

Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers).

+
//C
+void test() {
+   void (*foo)(void);
+   foo = 0;
+   foo(); // warn: function pointer is null
+ }
+
+ // C++
+ class C {
+ public:
+   void f();
+ };
+
+ void test() {
+   C *pc;
+   pc->f(); // warn: object pointer is uninitialized
+ }
+
+ // C++
+ class C {
+ public:
+   void f();
+ };
+
+ void test() {
+   C *pc = 0;
+   pc->f(); // warn: object pointer is null
+ }
+
+ // Objective-C
+ @interface MyClass : NSObject
+ @property (readwrite,assign) id x;
+ - (long double)longDoubleM;
+ @end
+
+ void test() {
+   MyClass *obj1;
+   long double ld1 = [obj1 longDoubleM];
+     // warn: receiver is uninitialized
+ }
+
+ // Objective-C
+ @interface MyClass : NSObject
+ @property (readwrite,assign) id x;
+ - (long double)longDoubleM;
+ @end
+
+ void test() {
+   MyClass *obj1;
+   id i = obj1.x; // warn: uninitialized object pointer
+ }
+
+ // Objective-C
+ @interface Subscriptable : NSObject
+ - (id)objectAtIndexedSubscript:(unsigned int)index;
+ @end
+
+ @interface MyClass : Subscriptable
+ @property (readwrite,assign) id x;
+ - (long double)longDoubleM;
+ @end
+
+ void test() {
+   MyClass *obj1;
+   id i = obj1[0]; // warn: uninitialized object pointer
+ }
+

(Clang-Tidy original name: clang-analyzer-core.CallAndMessage)

+ + +#### Divide Zero {#CT_SA_COR_DZ} +

Check for division by zero.

+
void test(int z) {
+  if (z == 0)
+    int x = 1 / z; // warn
+}
+
+void test() {
+  int x = 1;
+  int y = x % 0; // warn
+}
+

(Clang-Tidy original name: clang-analyzer-core.DivideZero)

+ + +#### Dynamic Type Propagation {#CT_SA_COR_DTP} +No documentation is available. + +#### Non Nil String Constants {#CT_SA_COR_NNSC} +No documentation is available. + +#### Non Null Param Checker {#CT_SA_COR_NNPC} +

Check for null pointers passed as arguments to a function whose arguments are references or marked with the ‘nonnull’ attribute.

+
int f(int *p) __attribute__((nonnull));
+
+void test(int *p) {
+  if (!p)
+    f(p); // warn
+}
+

(Clang-Tidy original name: clang-analyzer-core.NonNullParamChecker)

+ + +#### Null Dereference {#CT_SA_COR_ND} +

Check for dereferences of null pointers.

+
// C
+void test(int *p) {
+  if (p)
+    return;
+
+  int x = p[0]; // warn
+}
+
+// C
+void test(int *p) {
+  if (!p)
+    *p = 0; // warn
+}
+
+// C++
+class C {
+public:
+  int x;
+};
+
+void test() {
+  C *pc = 0;
+  int k = pc->x; // warn
+}
+
+// Objective-C
+@interface MyClass {
+@public
+  int x;
+}
+@end
+
+void test() {
+  MyClass *obj = 0;
+  obj->x = 1; // warn
+}
+

(Clang-Tidy original name: clang-analyzer-core.NullDereference)

+ + +#### Stack Address Escape {#CT_SA_COR_SAE} +

Check that addresses to stack memory do not escape the function.

+
char const *p;
+
+void test() {
+  char const str[] = "string";
+  p = str; // warn
+}
+
+void* test() {
+   return __builtin_alloca(12); // warn
+}
+
+void test() {
+  static int *x;
+  int y;
+  x = &y; // warn
+}
+

(Clang-Tidy original name: clang-analyzer-core.StackAddressEscape)

+ + +#### Stack Address Escape Base {#CT_SA_COR_SAEB} +No documentation is available. + +#### Undefined Binary Operator Result {#CT_SA_COR_UBOR} +

Check for undefined results of binary operators.

+
void test() {
+  int x;
+  int y = x + 1; // warn: left operand is garbage
+}
+

(Clang-Tidy original name: clang-analyzer-core.UndefinedBinaryOperatorResult)

+ + +#### VLA Size {#CT_SA_COR_VS} +

Check for declarations of Variable Length Arrays of undefined or zero size.

+

Check for declarations of VLA of undefined or zero size.

+
void test() {
+  int x;
+  int vla1[x]; // warn: garbage as size
+}
+
+void test() {
+  int x = 0;
+  int vla2[x]; // warn: zero size
+}
+

(Clang-Tidy original name: clang-analyzer-core.VLASize)

+ + +### Static Analyzer - Core/Builtin + +#### Builtin Functions {#CT_SA_BLT_BF} +No documentation is available. + +#### No Return Functions {#CT_SA_BLT_NRF} +No documentation is available. + +### Static Analyzer - Core/Uninitialized + +#### Array Subscript {#CT_SA_UIN_AS} +

Check for uninitialized values used as array subscripts.

+
void test() {
+  int i, a[10];
+  int x = a[i]; // warn: array subscript is undefined
+}
+

(Clang-Tidy original name: clang-analyzer-core.uninitialized.ArraySubscript)

+ + +#### Assign {#CT_SA_UIN_A} +

Check for assigning uninitialized values.

+
void test() {
+  int x;
+  x |= 1; // warn: left expression is uninitialized
+}
+

(Clang-Tidy original name: clang-analyzer-core.uninitialized.Assign)

+ + +#### Branch {#CT_SA_UIN_B} +

Check for uninitialized values used as branch conditions.

+
void test() {
+  int x;
+  if (x) // warn
+    return;
+}
+

(Clang-Tidy original name: clang-analyzer-core.uninitialized.Branch)

+ + +#### Captured Block Variable {#CT_SA_UIN_CBV} +

Check for blocks that capture uninitialized values.

+
void test() {
+  int x;
+  ^{ int y = x; }(); // warn
+}
+

(Clang-Tidy original name: clang-analyzer-core.uninitialized.CapturedBlockVariable)

+ + +#### Undef Return {#CT_SA_UIN_UR} +

Check for uninitialized values being returned to the caller.

+
int test() {
+  int x;
+  return x; // warn
+}
+

(Clang-Tidy original name: clang-analyzer-core.uninitialized.UndefReturn)

+ + +### Static Analyzer - Dead Code + +#### Dead Stores {#CT_SA_DCD_DS} +

Check for values stored to variables that are never read afterwards.

+
void test() {
+  int x;
+  x = 1; // warn
+}
+

The WarnForDeadNestedAssignments option enables the checker to emit warnings for nested dead assignments. You can disable with the -analyzer-config deadcode.DeadStores:WarnForDeadNestedAssignments=false. Defaults to true.

+

Would warn for this e.g.: if ((y = make_int())) { }

+

(Clang-Tidy original name: clang-analyzer-deadcode.DeadStores)

+ + +### Static Analyzer - Fuchsia + +#### Handle Checker {#CT_SA_FCS_HC} +

Handles identify resources. Similar to pointers they can be leaked, double freed, or use after freed. This check attempts to find such problems.

+
void checkLeak08(int tag) {
+  zx_handle_t sa, sb;
+  zx_channel_create(0, &sa, &sb);
+  if (tag)
+    zx_handle_close(sa);
+  use(sb); // Warn: Potential leak of handle
+  zx_handle_close(sb);
+}
+

(Clang-Tidy original name: clang-analyzer-fuchsia.HandleChecker)

+ + +### Static Analyzer - Nullability + +#### Null Passed To Nonnull {#CT_SA_NUL_NPTN2} +

Warns when a null pointer is passed to a pointer which has a _Nonnull type.

+
if (name != nil)
+  return;
+// Warning: nil passed to a callee that requires a non-null 1st parameter
+NSString *greeting = [@"Hello " stringByAppendingString:name];
+

(Clang-Tidy original name: clang-analyzer-nullability.NullPassedToNonnull)

+ + +#### Null Returned From Nonnull {#CT_SA_NUL_NRFN2} +

Warns when a null pointer is returned from a function that has _Nonnull return type.

+
- (nonnull id)firstChild {
+  id result = nil;
+  if ([_children count] > 0)
+    result = _children[0];
+
+  // Warning: nil returned from a method that is expected
+  // to return a non-null value
+  return result;
+}
+

(Clang-Tidy original name: clang-analyzer-nullability.NullReturnedFromNonnull)

+ + +#### Nullability Base {#CT_SA_NUL_NB} +No documentation is available. + +#### Nullable Dereferenced {#CT_SA_NUL_ND} +

Warns when a nullable pointer is dereferenced.

+
struct LinkedList {
+  int data;
+  struct LinkedList *next;
+};
+
+struct LinkedList * _Nullable getNext(struct LinkedList *l);
+
+void updateNextData(struct LinkedList *list, int newData) {
+  struct LinkedList *next = getNext(list);
+  // Warning: Nullable pointer is dereferenced
+  next->data = 7;
+}
+

(Clang-Tidy original name: clang-analyzer-nullability.NullableDereferenced)

+ + +#### Nullable Passed To Nonnull {#CT_SA_NUL_NPTN} +

Warns when a nullable pointer is passed to a pointer which has a _Nonnull type.

+
typedef struct Dummy { int val; } Dummy;
+Dummy *_Nullable returnsNullable();
+void takesNonnull(Dummy *_Nonnull);
+
+void test() {
+  Dummy *p = returnsNullable();
+  takesNonnull(p); // warn
+}
+

(Clang-Tidy original name: clang-analyzer-nullability.NullablePassedToNonnull)

+ + +#### Nullable Returned From Nonnull {#CT_SA_NUL_NRFN} +

Warns when a nullable pointer is returned from a function that has _Nonnull return type.

+

(Clang-Tidy original name: clang-analyzer-nullability.NullableReturnedFromNonnull)

+ + +### Static Analyzer - OptIn/C++ + +#### Uninitialized Object {#CT_SA_OI_CPP_UO} +

This checker reports uninitialized fields in objects created after a constructor call. It doesn’t only find direct uninitialized fields, but rather makes a deep inspection of the object, analyzing all of it’s fields subfields. The checker regards inherited fields as direct fields, so one will receive warnings for uninitialized inherited data members as well.

+
// With Pedantic and CheckPointeeInitialization set to true
+
+struct A {
+  struct B {
+    int x; // note: uninitialized field 'this->b.x'
+    // note: uninitialized field 'this->bptr->x'
+    int y; // note: uninitialized field 'this->b.y'
+    // note: uninitialized field 'this->bptr->y'
+  };
+  int *iptr; // note: uninitialized pointer 'this->iptr'
+  B b;
+  B *bptr;
+  char *cptr; // note: uninitialized pointee 'this->cptr'
+
+  A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {}
+};
+
+void f() {
+  A::B b;
+  char c;
+  A a(&b, &c); // warning: 6 uninitialized fields
+ //          after the constructor call
+}
+
+// With Pedantic set to false and
+// CheckPointeeInitialization set to true
+// (every field is uninitialized)
+
+struct A {
+  struct B {
+    int x;
+    int y;
+  };
+  int *iptr;
+  B b;
+  B *bptr;
+  char *cptr;
+
+  A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {}
+};
+
+void f() {
+  A::B b;
+  char c;
+  A a(&b, &c); // no warning
+}
+
+// With Pedantic set to true and
+// CheckPointeeInitialization set to false
+// (pointees are regarded as initialized)
+
+struct A {
+  struct B {
+    int x; // note: uninitialized field 'this->b.x'
+    int y; // note: uninitialized field 'this->b.y'
+  };
+  int *iptr; // note: uninitialized pointer 'this->iptr'
+  B b;
+  B *bptr;
+  char *cptr;
+
+  A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {}
+};
+
+void f() {
+  A::B b;
+  char c;
+  A a(&b, &c); // warning: 3 uninitialized fields
+ //          after the constructor call
+}
+

Options

+

This checker has several options which can be set from command line (e.g. -analyzer-config optin.cplusplus.UninitializedObject:Pedantic=true):

+
    +
  • Pedantic (boolean). If to false, the checker won’t emit warnings for objects that don’t have at least one initialized field. Defaults to false.
  • +
  • NotesAsWarnings (boolean). If set to true, the checker will emit a warning for each uninitialized field, as opposed to emitting one warning per constructor call, and listing the uninitialized fields that belongs to it in notes. Defaults to false.
  • +
  • CheckPointeeInitialization (boolean). If set to false, the checker will not analyze the pointee of pointer/reference fields, and will only check whether the object itself is initialized. Defaults to false.
  • +
  • IgnoreRecordsWithField (string). If supplied, the checker will not analyze structures that have a field with a name or type name that matches the given pattern. Defaults to “”.
  • +
+

(Clang-Tidy original name: clang-analyzer-optin.cplusplus.UninitializedObject)

+ + +#### Virtual Call {#CT_SA_OI_CPP_VC} +

Check virtual function calls during construction or destruction.

+
class A {
+public:
+  A() {
+    f(); // warn
+  }
+  virtual void f();
+};
+
+class A {
+public:
+  ~A() {
+    this->f(); // warn
+  }
+  virtual void f();
+};
+

(Clang-Tidy original name: clang-analyzer-optin.cplusplus.VirtualCall)

+ + +### Static Analyzer - OptIn/Cocoa Localizability + +#### Empty Localization Context Checker {#CT_SA_OI_OSX_LOC_ELCC} +

Check that NSLocalizedString macros include a comment for context.

+
- (void)test {
+  NSString *string = NSLocalizedString(@"LocalizedString", nil); // warn
+  NSString *string2 = NSLocalizedString(@"LocalizedString", @" "); // warn
+  NSString *string3 = NSLocalizedStringWithDefaultValue(
+    @"LocalizedString", nil, [[NSBundle alloc] init], nil,@""); // warn
+}
+

(Clang-Tidy original name: clang-analyzer-optin.osx.cocoa.localizability.EmptyLocalizationContextChecker)

+ + +#### Non Localized String Checker {#CT_SA_OI_OSX_LOC_NLSC} +

Warns about uses of non-localized NSStrings passed to UI methods expecting localized NSStrings.

+
NSString *alarmText =
+  NSLocalizedString(@"Enabled", @"Indicates alarm is turned on");
+if (!isEnabled) {
+  alarmText = @"Disabled";
+}
+UILabel *alarmStateLabel = [[UILabel alloc] init];
+
+// Warning: User-facing text should use localized string macro
+[alarmStateLabel setText:alarmText];
+

(Clang-Tidy original name: clang-analyzer-optin.osx.cocoa.localizability.NonLocalizedStringChecker)

+ + +### Static Analyzer - OptIn/MPI + +#### MPI-Checker {#CT_SA_OI_MPI_M} +

Checks MPI code.

+
void test() {
+  double buf = 0;
+  MPI_Request sendReq1;
+  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM,
+      0, MPI_COMM_WORLD, &sendReq1);
+} // warn: request 'sendReq1' has no matching wait.
+
+void test() {
+  double buf = 0;
+  MPI_Request sendReq;
+  MPI_Isend(&buf, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &sendReq);
+  MPI_Irecv(&buf, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &sendReq); // warn
+  MPI_Isend(&buf, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &sendReq); // warn
+  MPI_Wait(&sendReq, MPI_STATUS_IGNORE);
+}
+
+void missingNonBlocking() {
+  int rank = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+  MPI_Request sendReq1[10][10][10];
+  MPI_Wait(&sendReq1[1][7][9], MPI_STATUS_IGNORE); // warn
+}
+

(Clang-Tidy original name: clang-analyzer-optin.mpi.MPI-Checker)

+ + +### Static Analyzer - OptIn/Performance + +#### GCD Antipattern {#CT_SA_OI_PRF_GA} +

Check for performance anti-patterns when using Grand Central Dispatch.

+

(Clang-Tidy original name: clang-analyzer-optin.performance.GCDAntipattern)

+ + +#### Padding {#CT_SA_OI_PRF_P} +

Check for excessively padded structs.

+

(Clang-Tidy original name: clang-analyzer-optin.performance.Padding)

+ + +### Static Analyzer - OptIn/Portability + +#### Unix API {#CT_SA_OI_PRT_UA} +

Finds implementation-defined behavior in UNIX/Posix functions.

+

(Clang-Tidy original name: clang-analyzer-optin.portability.UnixAPI)

+ + +### Static Analyzer - OptIn/macOS + +#### OSObject C-Style Cast {#CT_SA_OI_OSX_OCC} +No documentation is available. + +### Static Analyzer - Security + +#### Float Loop Counter {#CT_SA_SEC_FLC} +

Warn on using a floating point value as a loop counter (CERT: FLP30-C, FLP30-CPP).

+
void test() {
+  for (float x = 0.1f; x <= 1.0f; x += 0.1f) {} // warn
+}
+

(Clang-Tidy original name: clang-analyzer-security.FloatLoopCounter)

+ + +### Static Analyzer - Security/Insecure API + +#### Deprecated Or Unsafe Buffer Handling {#CT_SA_SEC_DOUBH} +

Warn on occurrences of unsafe or deprecated buffer handling functions, which now have a secure variant: sprintf, vsprintf, scanf, wscanf, fscanf, fwscanf, vscanf, vwscanf, vfscanf, vfwscanf, sscanf, swscanf, vsscanf, vswscanf, swprintf, snprintf, vswprintf, vsnprintf, memcpy, memmove, strncpy, strncat, memset

+
void test() {
+  char buf [5];
+  strncpy(buf, "a", 1); // warn
+}
+

(Clang-Tidy original name: clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)

+ + +#### Security Syntax Checker {#CT_SA_SEC_SSC} +No documentation is available. + +#### Unchecked Return {#CT_SA_SEC_UR} +

Warn on uses of functions whose return values must be always checked.

+
void test() {
+  setuid(1); // warn
+}
+

(Clang-Tidy original name: clang-analyzer-security.insecureAPI.UncheckedReturn)

+ + +#### bcmp {#CT_SA_SEC_B} +

Warn on uses of the ‘bcmp’ function.

+
void test() {
+  bcmp(ptr0, ptr1, n); // warn
+}
+

(Clang-Tidy original name: clang-analyzer-security.insecureAPI.bcmp)

+ + +#### bcopy {#CT_SA_SEC_B2} +

Warn on uses of the ‘bcopy’ function.

+
void test() {
+  bcopy(src, dst, n); // warn
+}
+

(Clang-Tidy original name: clang-analyzer-security.insecureAPI.bcopy)

+ + +#### bzero {#CT_SA_SEC_B3} +

Warn on uses of the ‘bzero’ function.

+
void test() {
+  bzero(ptr, n); // warn
+}
+

(Clang-Tidy original name: clang-analyzer-security.insecureAPI.bzero)

+ + +#### decode Value Of ObjC Type {#CT_SA_SEC_DVOOT} +No documentation is available. + +#### getpw {#CT_SA_SEC_G} +

Warn on uses of the ‘getpw’ function.

+
void test() {
+  char buff[1024];
+  getpw(2, buff); // warn
+}
+

(Clang-Tidy original name: clang-analyzer-security.insecureAPI.getpw)

+ + +#### gets {#CT_SA_SEC_G2} +

Warn on uses of the ‘gets’ function.

+
void test() {
+  char buff[1024];
+  gets(buff); // warn
+}
+

(Clang-Tidy original name: clang-analyzer-security.insecureAPI.gets)

+ + +#### mkstemp {#CT_SA_SEC_M} +

Warn when ‘mkstemp’ is passed fewer than 6 X’s in the format string.

+
void test() {
+  mkstemp("XX"); // warn
+}
+

(Clang-Tidy original name: clang-analyzer-security.insecureAPI.mkstemp)

+ + +#### mktemp {#CT_SA_SEC_M2} +

Warn on uses of the mktemp function.

+
void test() {
+  char *x = mktemp("/tmp/zxcv"); // warn: insecure, use mkstemp
+}
+

(Clang-Tidy original name: clang-analyzer-security.insecureAPI.mktemp)

+ + +#### rand {#CT_SA_SEC_R} +

Warn on uses of inferior random number generating functions (only if arc4random function is available): drand48, erand48, jrand48, lcong48, lrand48, mrand48, nrand48, random, rand_r.

+
void test() {
+  random(); // warn
+}
+

(Clang-Tidy original name: clang-analyzer-security.insecureAPI.rand)

+ + +#### strcpy {#CT_SA_SEC_S} +

Warn on uses of the strcpy and strcat functions.

+
void test() {
+  char x[4];
+  char *y = "abcd";
+
+  strcpy(x, y); // warn
+}
+

(Clang-Tidy original name: clang-analyzer-security.insecureAPI.strcpy)

+ + +#### vfork {#CT_SA_SEC_V} +

Warn on uses of the ‘vfork’ function.

+
void test() {
+  vfork(); // warn
+}
+

(Clang-Tidy original name: clang-analyzer-security.insecureAPI.vfork)

+ + +### Static Analyzer - Unix + +#### API {#CT_SA_UNX_A} +

Check calls to various UNIX/Posix functions: open, pthread_once, calloc, malloc, realloc, alloca.

+

+// Currently the check is performed for apple targets only.
+void test(const char *path) {
+  int fd = open(path, O_CREAT);
+    // warn: call to 'open' requires a third argument when the
+    // 'O_CREAT' flag is set
+}
+
+void f();
+
+void test() {
+  pthread_once_t pred = {0x30B1BCBA, {0}};
+  pthread_once(&pred, f);
+    // warn: call to 'pthread_once' uses the local variable
+}
+
+void test() {
+  void *p = malloc(0); // warn: allocation size of 0 bytes
+}
+
+void test() {
+  void *p = calloc(0, 42); // warn: allocation size of 0 bytes
+}
+
+void test() {
+  void *p = malloc(1);
+  p = realloc(p, 0); // warn: allocation size of 0 bytes
+}
+
+void test() {
+  void *p = alloca(0); // warn: allocation size of 0 bytes
+}
+
+void test() {
+  void *p = valloc(0); // warn: allocation size of 0 bytes
+}
+
+

(Clang-Tidy original name: clang-analyzer-unix.API)

+ + +#### Malloc {#CT_SA_UNX_M} +

Check for memory leaks, double free, and use-after-free problems. Traces memory managed by malloc()/free().

+

+void test() {
+  int *p = malloc(1);
+  free(p);
+  free(p); // warn: attempt to free released memory
+}
+
+void test() {
+  int *p = malloc(sizeof(int));
+  free(p);
+  *p = 1; // warn: use after free
+}
+
+void test() {
+  int *p = malloc(1);
+  if (p)
+    return; // warn: memory is never released
+}
+
+void test() {
+  int a[] = { 1 };
+  free(a); // warn: argument is not allocated by malloc
+}
+
+void test() {
+  int *p = malloc(sizeof(char));
+  p = p - 1;
+  free(p); // warn: argument to free() is offset by -4 bytes
+}
+
+

(Clang-Tidy original name: clang-analyzer-unix.Malloc)

+ + +#### Malloc Sizeof {#CT_SA_UNX_MS} +

Check for dubious malloc arguments involving sizeof.

+
void test() {
+  long *p = malloc(sizeof(short));
+    // warn: result is converted to 'long *', which is
+    // incompatible with operand type 'short'
+  free(p);
+}
+

(Clang-Tidy original name: clang-analyzer-unix.MallocSizeof)

+ + +#### Mismatched Deallocator {#CT_SA_UNX_MD} +

Check for mismatched deallocators.

+
// C, C++
+void test() {
+  int *p = (int *)malloc(sizeof(int));
+  delete p; // warn
+}
+
+// C, C++
+void __attribute((ownership_returns(malloc))) *user_malloc(size_t);
+
+void test() {
+  int *p = (int *)user_malloc(sizeof(int));
+  delete p; // warn
+}
+
+// C, C++
+void test() {
+  int *p = new int;
+  free(p); // warn
+}
+
+// C, C++
+void test() {
+  int *p = new int[1];
+  realloc(p, sizeof(long)); // warn
+}
+
+// C, C++
+template <typename T>
+struct SimpleSmartPointer {
+  T *ptr;
+
+  explicit SimpleSmartPointer(T *p = 0) : ptr(p) {}
+  ~SimpleSmartPointer() {
+    delete ptr; // warn
+  }
+};
+
+void test() {
+  SimpleSmartPointer<int> a((int *)malloc(4));
+}
+
+// C++
+void test() {
+  int *p = (int *)operator new(0);
+  delete[] p; // warn
+}
+
+// Objective-C, C++
+void test(NSUInteger dataLength) {
+  int *p = new int;
+  NSData *d = [NSData dataWithBytesNoCopy:p
+               length:sizeof(int) freeWhenDone:1];
+    // warn +dataWithBytesNoCopy:length:freeWhenDone: cannot take
+    // ownership of memory allocated by 'new'
+}
+
+

(Clang-Tidy original name: clang-analyzer-unix.MismatchedDeallocator)

+ + +#### Vfork {#CT_SA_UNX_V} +

Check for proper usage of vfork.

+
int test(int x) {
+  pid_t pid = vfork(); // warn
+  if (pid != 0)
+    return 0;
+
+  switch (x) {
+  case 0:
+    pid = 1;
+    execl("", "", 0);
+    _exit(1);
+    break;
+  case 1:
+    x = 0; // warn: this assignment is prohibited
+    break;
+  case 2:
+    foo(); // warn: this function call is prohibited
+    break;
+  default:
+    return 0; // warn: return is prohibited
+  }
+
+  while(1);
+}
+

(Clang-Tidy original name: clang-analyzer-unix.Vfork)

+ + +### Static Analyzer - Unix/C string + +#### Bad Size Arg {#CT_SA_UNX_BSA} +

Check the size argument passed into C string functions for common erroneous patterns. Use -Wno-strncat-size compiler option to mute other strncat-related compiler warnings.

+
void test() {
+  char dest[3];
+  strncat(dest, """""""""""""""""""""""""*", sizeof(dest));
+    // warn: potential buffer overflow
+}
+

(Clang-Tidy original name: clang-analyzer-unix.cstring.BadSizeArg)

+ + +#### Null Arg {#CT_SA_UNX_NA} +

Check for null pointers being passed as arguments to C string functions: strlen, strnlen, strcpy, strncpy, strcat, strncat, strcmp, strncmp, strcasecmp, strncasecmp.

+
int test() {
+  return strlen(0); // warn
+}
+

(Clang-Tidy original name: clang-analyzer-unix.cstring.NullArg)

+ + +### Static Analyzer - Webkit + +#### No Uncounted Member Checker {#CT_SA_WBK_NUMC} +

Raw pointers and references to uncounted types can’t be used as class members. Only ref-counted types are allowed.

+
struct RefCntbl {
+  void ref() {}
+  void deref() {}
+};
+
+struct Foo {
+  RefCntbl * ptr; // warn
+  RefCntbl & ptr; // warn
+  // ...
+};
+

(Clang-Tidy original name: clang-analyzer-webkit.NoUncountedMemberChecker)

+ + +#### Ref Cntbl Base Virtual Dtor {#CT_SA_WBK_RCBVD} +

All uncounted types used as base classes must have a virtual destructor.

+

Ref-counted types hold their ref-countable data by a raw pointer and allow implicit upcasting from ref-counted pointer to derived type to ref-counted pointer to base type. This might lead to an object of (dynamic) derived type being deleted via pointer to the base class type which C++ standard defines as UB in case the base class doesn’t have virtual destructor [expr.delete].

+
struct RefCntblBase {
+  void ref() {}
+  void deref() {}
+};
+
+struct Derived : RefCntblBase { }; // warn
+

(Clang-Tidy original name: clang-analyzer-webkit.RefCntblBaseVirtualDtor)

+ + +#### Uncounted Lambda Captures Checker {#CT_SA_WBK_ULCC} +No documentation is available. + +### Static Analyzer - macOS + +#### API {#CT_SA_OSX_A} +

Check for proper uses of various Apple APIs.

+
void test() {
+  dispatch_once_t pred = 0;
+  dispatch_once(&pred, ^(){}); // warn: dispatch_once uses local
+}
+

(Clang-Tidy original name: clang-analyzer-osx.API)

+ + +#### Mach Interface Generator Calling Convention {#CT_SA_OSX_MIGCC} +No documentation is available. + +#### Ns Or CF Error Deref Checker {#CT_SA_OSX_NOCEDC} +No documentation is available. + +#### Number Object Conversion {#CT_SA_OSX_NOC} +

Check for erroneous conversions of objects representing numbers into numbers.

+
NSNumber *photoCount = [albumDescriptor objectForKey:@"PhotoCount"];
+// Warning: Comparing a pointer value of type 'NSNumber *'
+// to a scalar integer value
+if (photoCount > 0) {
+  [self displayPhotos];
+}
+

(Clang-Tidy original name: clang-analyzer-osx.NumberObjectConversion)

+ + +#### OSObject Retain Count {#CT_SA_OSX_ORC} +No documentation is available. + +#### Obj C Property {#CT_SA_OSX_OCP} +

Check for proper uses of Objective-C properties.

+
NSNumber *photoCount = [albumDescriptor objectForKey:@"PhotoCount"];
+// Warning: Comparing a pointer value of type 'NSNumber *'
+// to a scalar integer value
+if (photoCount > 0) {
+  [self displayPhotos];
+}
+

(Clang-Tidy original name: clang-analyzer-osx.ObjCProperty)

+ + +#### Sec Keychain API {#CT_SA_OSX_SKA} +

Check for proper uses of Secure Keychain APIs.

+
void test() {
+  unsigned int *ptr = 0;
+  UInt32 length;
+
+  SecKeychainItemFreeContent(ptr, &length);
+    // warn: trying to free data which has not been allocated
+}
+
+void test() {
+  unsigned int *ptr = 0;
+  UInt32 *length = 0;
+  void *outData;
+
+  OSStatus st =
+    SecKeychainItemCopyContent(2, ptr, ptr, length, outData);
+    // warn: data is not released
+}
+
+void test() {
+  unsigned int *ptr = 0;
+  UInt32 *length = 0;
+  void *outData;
+
+  OSStatus st =
+    SecKeychainItemCopyContent(2, ptr, ptr, length, &outData);
+
+  SecKeychainItemFreeContent(ptr, outData);
+    // warn: only call free if a non-NULL buffer was returned
+}
+
+void test() {
+  unsigned int *ptr = 0;
+  UInt32 *length = 0;
+  void *outData;
+
+  OSStatus st =
+    SecKeychainItemCopyContent(2, ptr, ptr, length, &outData);
+
+  st = SecKeychainItemCopyContent(2, ptr, ptr, length, &outData);
+    // warn: release data before another call to the allocator
+
+  if (st == noErr)
+    SecKeychainItemFreeContent(ptr, outData);
+}
+
+void test() {
+  SecKeychainItemRef itemRef = 0;
+  SecKeychainAttributeInfo *info = 0;
+  SecItemClass *itemClass = 0;
+  SecKeychainAttributeList *attrList = 0;
+  UInt32 *length = 0;
+  void *outData = 0;
+
+  OSStatus st =
+    SecKeychainItemCopyAttributesAndData(itemRef, info,
+                                         itemClass, &attrList,
+                                         length, &outData);
+
+  SecKeychainItemFreeContent(attrList, outData);
+    // warn: deallocator doesn't match the allocator
+}
+

(Clang-Tidy original name: clang-analyzer-osx.SecKeychainAPI)

+ + +### Static Analyzer - macOS/Cocoa API + +#### At Sync {#CT_SA_OSX_CCA_AS} +

Check for nil pointers used as mutexes for @synchronized.

+
void test(id x) {
+  if (!x)
+    @synchronized(x) {} // warn: nil value used as mutex
+}
+
+void test() {
+  id y;
+  @synchronized(y) {} // warn: uninitialized value used as mutex
+}
+

(Clang-Tidy original name: clang-analyzer-osx.cocoa.AtSync)

+ + +#### Autorelease Write {#CT_SA_OSX_CCA_AW} +

Warn about potentially crashing writes to autoreleasing objects from different autoreleasing pools in Objective-C.

+

(Clang-Tidy original name: clang-analyzer-osx.cocoa.AutoreleaseWrite)

+ + +#### Class Release {#CT_SA_OSX_CCA_CR} +

Check for sending ‘retain’, ‘release’, or ‘autorelease’ directly to a Class.

+
@interface MyClass : NSObject
+@end
+
+void test(void) {
+  [MyClass release]; // warn
+}
+

(Clang-Tidy original name: clang-analyzer-osx.cocoa.ClassRelease)

+ + +#### Dealloc {#CT_SA_OSX_CCA_D} +

Warn about Objective-C classes that lack a correct implementation of -dealloc

+
@interface MyObject : NSObject {
+  id _myproperty;
+}
+@end
+
+@implementation MyObject // warn: lacks 'dealloc'
+@end
+
+@interface MyObject : NSObject {}
+@property(assign) id myproperty;
+@end
+
+@implementation MyObject // warn: does not send 'dealloc' to super
+- (void)dealloc {
+  self.myproperty = 0;
+}
+@end
+
+@interface MyObject : NSObject {
+  id _myproperty;
+}
+@property(retain) id myproperty;
+@end
+
+@implementation MyObject
+@synthesize myproperty = _myproperty;
+  // warn: var was retained but wasn't released
+- (void)dealloc {
+  [super dealloc];
+}
+@end
+
+@interface MyObject : NSObject {
+  id _myproperty;
+}
+@property(assign) id myproperty;
+@end
+
+@implementation MyObject
+@synthesize myproperty = _myproperty;
+  // warn: var wasn't retained but was released
+- (void)dealloc {
+  [_myproperty release];
+  [super dealloc];
+}
+@end
+

(Clang-Tidy original name: clang-analyzer-osx.cocoa.Dealloc)

+ + +#### Incompatible Method Types {#CT_SA_OSX_CCA_IMT} +

Warn about Objective-C method signatures with type incompatibilities.

+
@interface MyClass1 : NSObject
+- (int)foo;
+@end
+
+@implementation MyClass1
+- (int)foo { return 1; }
+@end
+
+@interface MyClass2 : MyClass1
+- (float)foo;
+@end
+
+@implementation MyClass2
+- (float)foo { return 1.0; } // warn
+@end
+

(Clang-Tidy original name: clang-analyzer-osx.cocoa.IncompatibleMethodTypes)

+ + +#### Loops {#CT_SA_OSX_CCA_L} +

Improved modeling of loops using Cocoa collection types.

+

(Clang-Tidy original name: clang-analyzer-osx.cocoa.Loops)

+ + +#### Missing Super Call {#CT_SA_OSX_CCA_MSC} +

Warn about Objective-C methods that lack a necessary call to super.

+
@interface Test : UIViewController
+@end
+@implementation test
+- (void)viewDidLoad {} // warn
+@end
+

(Clang-Tidy original name: clang-analyzer-osx.cocoa.MissingSuperCall)

+ + +#### NS Autorelease Pool {#CT_SA_OSX_CCA_NAP} +

Warn for suboptimal uses of NSAutoreleasePool in Objective-C GC mode.

+
void test() {
+  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+  [pool release]; // warn
+}
+

(Clang-Tidy original name: clang-analyzer-osx.cocoa.NSAutoreleasePool)

+ + +#### NS Error {#CT_SA_OSX_CCA_NE} +

Check usage of NSError parameters.

+
@interface A : NSObject
+- (void)foo:(NSError """""""""""""""""""""""")error;
+@end
+
+@implementation A
+- (void)foo:(NSError """""""""""""""""""""""")error {
+  // warn: method accepting NSError"""""""""""""""""""""""" should have a non-void
+  // return value
+}
+@end
+
+@interface A : NSObject
+- (BOOL)foo:(NSError """""""""""""""""""""""")error;
+@end
+
+@implementation A
+- (BOOL)foo:(NSError """""""""""""""""""""""")error {
+  *error = 0; // warn: potential null dereference
+  return 0;
+}
+@end
+

(Clang-Tidy original name: clang-analyzer-osx.cocoa.NSError)

+ + +#### Nil Arg {#CT_SA_OSX_CCA_NA} +

Check for prohibited nil arguments to ObjC method calls.

+
    +
  • caseInsensitiveCompare:
  • +
  • compare:
  • +
  • compare:options:
  • +
  • compare:options:range:
  • +
  • compare:options:range:locale:
  • +
  • componentsSeparatedByCharactersInSet:
  • +
  • initWithFormat:
  • +
+
NSComparisonResult test(NSString *s) {
+  NSString *aString = nil;
+  return [s caseInsensitiveCompare:aString];
+    // warn: argument to 'NSString' method
+    // 'caseInsensitiveCompare:' cannot be nil
+}
+

(Clang-Tidy original name: clang-analyzer-osx.cocoa.NilArg)

+ + +#### Non Nil Return Value {#CT_SA_OSX_CCA_NNRV} +

Models the APIs that are guaranteed to return a non-nil value.

+

(Clang-Tidy original name: clang-analyzer-osx.cocoa.NonNilReturnValue)

+ + +#### Obj C Generics {#CT_SA_OSX_CCA_OCG} +

Check for type errors when using Objective-C generics.

+
NSMutableArray *names = [NSMutableArray array];
+NSMutableArray *birthDates = names;
+
+// Warning: Conversion from value of type 'NSDate *'
+// to incompatible type 'NSString *'
+[birthDates addObject: [NSDate date]];
+

(Clang-Tidy original name: clang-analyzer-osx.cocoa.ObjCGenerics)

+ + +#### Retain Count {#CT_SA_OSX_CCA_RC} +

Check for leaks and improper reference count management

+
void test() {
+  NSString *s = [[NSString alloc] init]; // warn
+}
+
+CFStringRef test(char *bytes) {
+  return CFStringCreateWithCStringNoCopy(
+           0, bytes, NSNEXTSTEPStringEncoding, 0); // warn
+}
+

(Clang-Tidy original name: clang-analyzer-osx.cocoa.RetainCount)

+ + +#### Retain Count Base {#CT_SA_OSX_CCA_RCB} +No documentation is available. + +#### Run Loop Autorelease Leak {#CT_SA_OSX_CCA_RLAL} +

Check for leaked memory in autorelease pools that will never be drained.

+

(Clang-Tidy original name: clang-analyzer-osx.cocoa.RunLoopAutoreleaseLeak)

+ + +#### Self Init {#CT_SA_OSX_CCA_SI} +

Check that ‘self’ is properly initialized inside an initializer method.

+
@interface MyObj : NSObject {
+  id x;
+}
+- (id)init;
+@end
+
+@implementation MyObj
+- (id)init {
+  [super init];
+  x = 0; // warn: instance variable used while 'self' is not
+         // initialized
+  return 0;
+}
+@end
+
+@interface MyObj : NSObject
+- (id)init;
+@end
+
+@implementation MyObj
+- (id)init {
+  [super init];
+  return self; // warn: returning uninitialized 'self'
+}
+@end
+

(Clang-Tidy original name: clang-analyzer-osx.cocoa.SelfInit)

+ + +#### Super Dealloc {#CT_SA_OSX_CCA_SD} +

Warn about improper use of ‘super dealloc’ in Objective-C.

+
@interface SuperDeallocThenReleaseIvarClass : NSObject {
+  NSObject *_ivar;
+}
+@end
+
+@implementation SuperDeallocThenReleaseIvarClass
+- (void)dealloc {
+  [super dealloc];
+  [_ivar release]; // warn
+}
+@end
+

(Clang-Tidy original name: clang-analyzer-osx.cocoa.SuperDealloc)

+ + +#### Unused Ivars {#CT_SA_OSX_CCA_UI} +

Warn about private ivars that are never used.

+
@interface MyObj : NSObject {
+@private
+  id x; // warn
+}
+@end
+
+@implementation MyObj
+@end
+

(Clang-Tidy original name: clang-analyzer-osx.cocoa.UnusedIvars)

+ + +#### Variadic Method Types {#CT_SA_OSX_CCA_VMT} +

Check for passing non-Objective-C types to variadic collection initialization methods that expect only Objective-C types.

+
void test() {
+  [NSSet setWithObjects:@"Foo", "Bar", nil];
+    // warn: argument should be an ObjC pointer type, not 'char *'
+}
+

(Clang-Tidy original name: clang-analyzer-osx.cocoa.VariadicMethodTypes)

+ + +### Static Analyzer - macOS/Core Foundation + +#### CF Error {#CT_SA_OSX_CRF_CE} +

Check usage of CFErrorRef* parameters

+
void test(CFErrorRef *error) {
+  // warn: function accepting CFErrorRef* should have a
+  // non-void return
+}
+
+int foo(CFErrorRef *error) {
+  *error = 0; // warn: potential null dereference
+  return 0;
+}
+

(Clang-Tidy original name: clang-analyzer-osx.coreFoundation.CFError)

+ + +#### CF Number {#CT_SA_OSX_CRF_CN} +

Check for proper uses of CFNumber APIs.

+
CFNumberRef test(unsigned char x) {
+  return CFNumberCreate(0, kCFNumberSInt16Type, &x);
+   // warn: 8 bit integer is used to initialize a 16 bit integer
+}
+

(Clang-Tidy original name: clang-analyzer-osx.coreFoundation.CFNumber)

+ + +#### CF Retain Release {#CT_SA_OSX_CRF_CRR} +

Check for null arguments to CFRetain/CFRelease/CFMakeCollectable.

+
void test(CFTypeRef p) {
+  if (!p)
+    CFRetain(p); // warn
+}
+
+void test(int x, CFTypeRef p) {
+  if (p)
+    return;
+
+  CFRelease(p); // warn
+}
+

(Clang-Tidy original name: clang-analyzer-osx.coreFoundation.CFRetainRelease)

+ + +### Static Analyzer - macOS/Core Foundation/Containers + +#### Out Of Bounds {#CT_SA_OSX_CRF_OOB} +

Checks for index out-of-bounds when using ‘CFArray’ API.

+
void test() {
+  CFArrayRef A = CFArrayCreate(0, 0, 0, &kCFTypeArrayCallBacks);
+  CFArrayGetValueAtIndex(A, 0); // warn
+}
+

(Clang-Tidy original name: clang-analyzer-osx.coreFoundation.containers.OutOfBounds)

+ + +#### Pointer Sized Values {#CT_SA_OSX_CRF_PSV} +

Warns if ‘CFArray’, ‘CFDictionary’, ‘CFSet’ are created with non-pointer-size values.

+
void test() {
+  int x[] = { 1 };
+  CFArrayRef A = CFArrayCreate(0, (const void """""""""""""""""""""""")x, 1,
+                               &kCFTypeArrayCallBacks); // warn
+}
+

(Clang-Tidy original name: clang-analyzer-osx.coreFoundation.containers.PointerSizedValues)

+ + +### Static Analyzer - va_list + +#### Copy To Self {#CT_SA_VAL_CTS} +No documentation is available. + +#### Uninitialized {#CT_SA_VAL_U} +No documentation is available. + +#### Unterminated {#CT_SA_VAL_U2} +No documentation is available. + +#### Valist Base {#CT_SA_VAL_VB} +No documentation is available. + +### Zircon + +#### Temporary Objects {#CT_ZRC_TO} +

Warns on construction of specific temporary objects in the Zircon kernel. If the object should be flagged, If the object should be flagged, the fully qualified type name must be explicitly passed to the check.

+

For example, given the list of classes “Foo” and “NS::Bar”, all of the following will trigger the warning:

+
Foo();
+Foo F = Foo();
+func(Foo());
+
+namespace NS {
+
+Bar();
+
+}
+

With the same list, the following will not trigger the warning:

+
Foo F;                 // Non-temporary construction okay
+Foo F(param);          // Non-temporary construction okay
+Foo *F = new Foo();    // New construction okay
+
+Bar();                 // Not NS::Bar, so okay
+NS::Bar B;             // Non-temporary construction okay
+

Note that objects must be explicitly specified in order to be flagged, and so objects that inherit a specified object will not be flagged.

+

This check matches temporary objects without regard for inheritance and so a prohibited base class type does not similarly prohibit derived class types.

+
class Derived : Foo {} // Derived is not explicitly disallowed
+Derived();             // and so temporary construction is okay
+
Options
+

Names

+

A semi-colon-separated list of fully-qualified names of C++ classes that should not be constructed as temporaries. Default is empty.

+

(Clang-Tidy original name: zircon-temporary-objects)

+ + diff --git a/OpenStaticAnalyzer/cpp/doc/usersguide/md/CodeDuplicationMetricsRef.md b/OpenStaticAnalyzer/cpp/doc/usersguide/md/CodeDuplicationMetricsRef.md new file mode 100644 index 0000000..758269a --- /dev/null +++ b/OpenStaticAnalyzer/cpp/doc/usersguide/md/CodeDuplicationMetricsRef.md @@ -0,0 +1,152 @@ +## Reference of code duplication metrics + +Code cloning (or copy-paste programming) means the copying of an existing piece of source code, pasting it somewhere else, and typically performing smaller modifications on it. Based on the level of similarity between the copied code fragments we can define the following duplication types: + +- **Type-1**: the copied code parts are identical code fragments except for variations in whitespace, layout and comments. + +- **Type-2**: syntactically identical fragments except for variations in identifier names, literals, type references, whitespace, layout and comments. + +- **Type-3**: copied fragments with further modifications such as altered, added, or removed statements, in addition to variations in identifier names, literals, type references, whitespace, layout and comments. + +- **Type-4**: the copied code fragments are syntactically different, but they perform the same functionality, i.e. they are semantically the same. + +OpenStaticAnalyzer is capable of identifying Type-2 clones, i.e. code fragments that are structurally identical, but may differ in variable names, literals, identifiers, etc. + +Two code segments correspond to each other if they are copies of each other. This relation is an equivalence relation and we use the notion of clone classes to the classes of the relation, and the members of the classes will be referred to as clone instances. Owing to the nature of the relation, each clone class must contain at least two clone instances. + +Clones are tracked during the source code analysis of consecutive revisions of the analyzed software system. OpenStaticAnalyzer detects suspicious, inconsistently changing code copies, which are called "clone smells". The smells concerning clone classes are the following: + +- **Disappearing Clone Class (DCC):** The clone class existed in the previously analyzed revision but it does not exist anymore. + +- **Appearing Clone Class (ACC):** The clone class did not exist in the previously analyzed revision. + +The smells concerning clone instances are issued only if the containing clone class does not contain any smell. These are the following: + +- **Disappearing Clone Instance (DCI):** The clone instance existed in the previously analyzed revision but it does not exist anymore. + +- **Appearing Clone Instance (ACI):** The clone instance did not exist in the previously analyzed revision. + +- **Moving Clone Instance (MCI):** The clone instance belonged to a different clone class in the previously analyzed revision than its current class. + +The following table summarizes the code duplication metrics, their abbreviations, and their correspondence to different source code element types. + + Metric name Abbrev. Clone Instance Clone Class Method, Function Class, Struct, Union, Interface, Enum Namespace Comp. + --------------------------------- -------- ---------------- ------------- ------------------ --------------------------------------- ----------- ------- + Clone Age CA X X + Clone Classes CCL X X X X + Clone Complexity CCO X X X X X X + Clone Coverage CC X X X X + Clone Elimination Effort CEE X X + Clone Elimination Gain CEG X X + Clone Embeddedness CE X X + Clone Instances CI X X X X X + Clone Line Coverage CLC X X X X + Clone Lines of Code CLLOC X X + Clone Logical Line Coverage CLLC X X X X + Clone Risk CR X X + Clone Variability CV X X + Lines of Duplicated Code LDC X X X X + Logical Lines of Duplicated Code LLDC X X X X + Normalized Clone Radius NCR X X + +### Clone metrics + +#### Clone Age (CA) {#CA} + +**Clone class/clone instance:** number of previously analyzed revisions in which the clone class/clone instance was present + 1. + +#### Clone Classes (CCL) {#CCL} + +**Method/class/package:** number of clone classes having at least one clone instance in the source code element. + +**Component:** number of clone classes having at least one clone instance in the component. + +#### Clone Complexity (CCO) {#CCO} + +**Clone instance:** the McCabe complexity of the code fragment corresponding to the clone instance. + +**Clone class:** sum of CCO of clone instances in the clone class. + +**Function/method/class/module/package:** sum of CCO of clone instances in the source code element. + +**Component:** sum of CCO of clone instances in the component. + +#### Clone Coverage (CC) {#CC} + +**Method/Function/Union/Enum/class/Structure/Namespace:** ratio of code covered by code duplications in the source code element to the size of the source code element, expressed in terms of the number of syntactic entities (statements, expressions, etc.). + +**Component:** ratio of code covered by code duplications in the component to the size of the component, expressed in terms of the number of syntactic entities (statements, expressions, etc.). + +#### Clone Elimination Effort (CEE) {#CEE} + +**Clone class:** index of the effort required to eliminate the clone class. It is computed as the product of CI, CE, and NCR. + +**Component:** index of the effort required to eliminate all clones from the component. It is computed as the sum of CEE of the clone classes in the component. + +#### Clone Elimination Gain (CEG) {#CEG} + +**Clone class:** index of the gain resulting from eliminating the clone class. It is computed as the ratio of CR to CEE. + +**Component:** index of the gain resulting from eliminating all clones from the component. It is computed as the logistic function of the ratio of CR to CEE. + +#### Clone Embeddedness (CE) {#CE} + +**Clone instance:** sum of incoming and outgoing references (function calls, variable references, type references; different references to the same entity are counted only once) in the code fragment corresponding to the clone instance, weighted with the number of directory changes between the referenced code fragments. + +**Clone class:** sum of CE of the clone instances of the clone class + 1. + +#### Clone Instances (CI) {#CI} + +**Method/class/package:** number of clone instances in the source code element. + +**Component:** number of clone instances in the component. + +**Clone class:** number of clone instances in the clone class. + +#### Clone Line Coverage (CLC) {#CLC} + +**Function/method/class/module/package:** ratio of code covered by code duplications in the source code element to the size of the source code element, expressed in terms of lines of code. + +**Component:** ratio of code covered by code duplications in the component to the size of the component, expressed in terms of lines of code. + +#### Clone Lines of Code (CLLOC) {#CLLOC} + +**Clone instance:** length of the clone instance expressed in terms of lines of code. + +**Clone class:** average of CLLOC of clone instances belonging to the clone class. + +#### Clone Logical Line Coverage (CLLC) {#CLLC} + +**Function/method/class/module/package:** ratio of code covered by code duplications in the source code element to the size of source code element, expressed in terms of logical lines of code (non-empty, non-comment lines). + +**Component:** ratio of code covered by code duplications in the component to the size of the component, expressed in terms of logical lines of code (non-empty, non-comment lines). + +#### Clone Risk (CR) {#CR} + +**Clone class:** risk index of the existence of the clone class. It is computed as the product of CLLOC, CI, CCO, NCR, and CV. + +**Component:** relative risk index of the existence of code duplications in the component. It is computed as the sum of CR of the clone classes in the component, divided by the total logical lines of code (non-empty, non-comment lines) of the component. It expresses the risk index projected to a non-empty, non-comment line of code in the component. + +#### Clone Variability (CV) {#CV} + +**Clone instance:** instability of the clone instance since it appeared. It is computed as the ratio of the number of previously analyzed revisions when the instance had been changed to its age (CA). + +**Clone class:** instability of the clone class since it appeared. It is computed as the ratio of the number of previously analyzed revisions when its contained instances were moved, deleted, or added, to its age (CA), plus the average CV of its clone instances. + +#### Lines of Duplicated Code (LDC) {#LDC} + +**Function/method/class/module/package:** number of code lines covered by code duplications in the source code element. + +**Component:** number of code lines covered by code duplications in the component. + +#### Logical Lines of Duplicated Code (LLDC) {#LLDC} + +**Function/method/class/module/package:** number of logical code lines (non-empty, non-comment lines) covered by code duplications in the source code element. + +**Component:** The number of logical code lines (non-empty, non-comment lines) covered by code duplications in the component. + +#### Normalized Clone Radius (NCR) {#NCR} + +**Clone class:** normalized average distance among clone instances belonging to the clone class, expressed in terms of number of directory changes. + +**Component:** average of NCR of the clone classes in the component. diff --git a/OpenStaticAnalyzer/cpp/doc/usersguide/md/CppcheckRef.md b/OpenStaticAnalyzer/cpp/doc/usersguide/md/CppcheckRef.md new file mode 100644 index 0000000..1ecaefd --- /dev/null +++ b/OpenStaticAnalyzer/cpp/doc/usersguide/md/CppcheckRef.md @@ -0,0 +1,1363 @@ +## Reference of Cppcheck coding rule violations + +Cppcheck is a static analysis tool for C/C++ code. Unlike C/C++ compilers and many other analysis tools it does not detect syntax errors in the code. Cppcheck primarily detects the types of bugs that the compilers normally do not detect. The goal is to detect only real errors in the code (i.e. have zero false positives). + +OpenStaticAnalyzer uses Cppcheck "as is", without any guaranties that the results of Cppcheck are correct. All statements of the Cppcheck license apply here as well. All texts describing the rulesets and the individual rules are copied from the cppcheck with some minor grammatical fixes. + +The list of rulesets and rules contained in each ruleset are the following: + +- **API Rules:** The API Ruleset contains rules that find built in function usages that are wrong. + +- **Boost Library Rules:** The Boost Library Ruleset contains rules for boost usage. + +- **Buffer Overrun Rules:** The Buffer Overrun Ruleset contains rules that find mistakes about buffers usage and array indices. + +- **Conditional Rules:** The Conditional Ruleset contains rules that find condition mistakes. + +- **Division Rules:** The Division Ruleset contains rules about the division operator. + +- **Exception Rules:** The Exception Ruleset contains rules about throwing and catching exceptions. + +- **Initialization Rules:** The Initialization Ruleset contains rules about the initialization of allocated memory, variables and members. + +- **Input Output Rules:** The Input Output Ruleset contains rules for input output operations. + +- **Memory Handling Rules:** The Memory Handling Ruleset contains rules about memory leaks and common memory management problems. + +- **Object Orientedness Rules:** The Object Orientedness Ruleset contains rules that find various mistakes about classes and other object orientedness related constructs. + +- **Performance Rules:** The Performance Ruleset contains rules that find various performance issues. + +- **Portability Rules:** The Portability Ruleset contains rules that find portability issues. + +- **Readability and Consistency Rules:** The Readability and Consistency Ruleset contains rules about constructs that reduce the code readability. + +- **STL Rules:** The STL Ruleset contains rules that find mistakes of STL usage (invalidation of iterators, mismatching containers, etc). + +- **Side Effect Rules:** The Side Effect Ruleset contains rules that find suspicious constructs that can have side effects. + +- **Simple Type Rules:** The Simple Type Ruleset contains rules that find simple type related issues. + +- **Sizeof Operator Rules:** The Sizeof Operator Ruleset contains rules that check usage of sizeof operator. + +- **Suspicious Construct Rules:** The Suspicious Construct Ruleset contains rules about constructs that are redundant or could lead to unexpected results. + +- **Unnecessary and Unused Code Rules:** The Unnecessary and Unused Code Ruleset contains a collection of rules for unnecessary,unused or ineffective code. + +- **Unreachable Code Rules:** The Unreachable Code Ruleset contains rules about code sections that can never be executed. + +- **Variable Argument Related Rules:** The Variable Argument Related Ruleset contains rules about the usage of va_start and va_end functions. + +The following table contains the enabled rules and their priorities: + + Category Name Abbreviation Prio. + ---------------------------------- ------------------------------------------------- ----------------- --------- + API Rules Invalid Function Argument Boolean CPPCHECK_IFAB Blocker + Invalid Function Argument String CPPCHECK_IFAS Blocker + Invalid Function Arguments CPPCHECK_IFA Blocker + Invalid Length Modifier Error CPPCHECK_ILME Critical + Memset Value Out Of Range CPPCHECK_MVOOR Critical + Memset Zero Bytes CPPCHECK_MZB Critical + Race After Interlocked Decrement CPPCHECK_RAID Blocker + Strncat Usage CPPCHECK_STRCU Critical + Unprecise Math Call CPPCHECK_UPMC Minor + Wrong Math Call CPPCHECK_WMC Critical + Wrong Pipe Parameter Size CPPCHECK_WPPS Blocker + Boost Library Rules Boost Foreach Error CPPCHECK_BFE Blocker + Buffer Overrun Rules Argument Size CPPCHECK_AS Critical + Array Index Out Of Bounds CPPCHECK_AIOOB Blocker + Array Index Out Of Bounds Cond CPPCHECK_AIOOBC Critical + Array Index Then Check CPPCHECK_AITC Minor + Buffer Access Out Of Bounds CPPCHECK_BAOOB Blocker + Buffer Not Zero Terminated CPPCHECK_BNZT Critical + Insecure Cmd Line Arguments CPPCHECK_ICLA Blocker + Negative Array Size CPPCHECK_NAS Blocker + Negative Index CPPCHECK_NI Blocker + Negative Memory Allocation Size CPPCHECK_NMAS Blocker + Out Of Bounds CPPCHECK_OOB Blocker + Pointer Out Of Bounds CPPCHECK_POOB Minor + Possible Buffer Access Out Of Bounds CPPCHECK_PBAOOB Critical + Size Argument As Char CPPCHECK_SAAC Critical + Terminate Strncpy CPPCHECK_TSTRC Critical + Conditional Rules Assign If Error CPPCHECK_AIE Minor + Bad Bitmask Check CPPCHECK_BBC Critical + Clarify Condition CPPCHECK_CCOND Minor + Comparison Error CPPCHECK_CE Minor + Comparison Function Is Always True Or False CPPCHECK_CFIATOF Critical + Comparison Of Bool With Invalid Comparator CPPCHECK_COBWIC Critical + Condition is Always False CPPCHECK_CAF Minor + Identical Condition After Early Exit CPPCHECK_ICAEE Critical + Identical Inner Condition CPPCHECK_IIC Critical + Incorrect Logic Operator CPPCHECK_ILO Critical + Invalid Test For Overflow CPPCHECK_ITFO Critical + Mismatching Bit And CPPCHECK_MBA Minor + Modulo Always True False CPPCHECK_MATF Critical + Multi Condition CPPCHECK_MCOND Minor + Opposite Inner Condition CPPCHECK_OIC Critical + Pointer Addition Null Check CPPCHECK_PANC Critical + Redundant Condition CPPCHECK_RCOND Minor + Division Rules Unsafe Class Can Divide By Zero CPPCHECK_UCCDBZ Minor + Zerodiv CPPCHECK_ZD Blocker + Zerodivcond CPPCHECK_ZDC Blocker + Exception Rules Catch Exception By Value CPPCHECK_CEBV Minor + Except Dealloc Throw CPPCHECK_EDT Critical + Except Rethrow Copy CPPCHECK_ERC Minor + Except Throw In Destructor CPPCHECK_ETID Critical + Throw In Noexcept Function CPPCHECK_TINF Blocker + Unhandled Exception Specification CPPCHECK_UES Minor + Initialization Rules Dangerous Use Of Strncpy CPPCHECK_DUOS Blocker + Deadpointer CPPCHECK_DP Blocker + Uninit Struct Member CPPCHECK_UISM Blocker + Uninitialized Data CPPCHECK_UID Blocker + Uninitialized Variable CPPCHECK_UIV Blocker + Input Output Rules Cout Cerr Misusage CPPCHECK_CCM Blocker + Fflush On Input Stream CPPCHECK_FOIS Minor + IO Without Positioning CPPCHECK_IOWP Blocker + Invalid Printf Arg Type_float CPPCHECK_IPATF Critical + Invalid Printf Arg Type_n CPPCHECK_IPATN Critical + Invalid Printf Arg Type_p CPPCHECK_IPATP Critical + Invalid Printf Arg Type_s CPPCHECK_IPATS Critical + Invalid Printf Arg Type_sint CPPCHECK_IPATSI Critical + Invalid Printf Arg Type_uint CPPCHECK_IPATUI Critical + Invalid Scanf CPPCHECK_IS Critical + Invalid Scanf Arg Type_float CPPCHECK_ISATF Critical + Invalid Scanf Arg Type_int CPPCHECK_ISATI Critical + Invalid Scanf Arg Type_s CPPCHECK_ISATS Critical + Invalid Scanf Format Width CPPCHECK_ISFW Blocker + Read Write Only File CPPCHECK_RWOF Blocker + Seek On Appended File CPPCHECK_SOAF Critical + Use Closed File CPPCHECK_UCF Blocker + Write Read Only File CPPCHECK_WROF Blocker + Wrong Printf Scanf Arg Num CPPCHECK_WPSAN Blocker + Wrong Printf Scanf Parameter Position Error CPPCHECK_WPSPPE Critical + Memory Handling Rules Access Forwarded CPPCHECK_AF Critical + Access Moved CPPCHECK_AM Critical + Auto Variables CPPCHECK_AV Blocker + Auto Variables Assign Global Pointer CPPCHECK_AVAGP Critical + Autovar Invalid Deallocation CPPCHECK_AID Blocker + Dangling Lifetime CPPCHECK_DL Blocker + Dealloc Dealloc CPPCHECK_DD Blocker + Deallocret CPPCHECK_DAR Blocker + Deallocuse CPPCHECK_DU Blocker + Double Free CPPCHECK_DF Blocker + Ignored Return Value CPPCHECK_IRV Critical + Incomplete Array Fill CPPCHECK_IAF Critical + Invalid Free CPPCHECK_IF Blocker + Invalid Lifetime CPPCHECK_ILT Blocker + Leak No Var Function Call CPPCHECK_LNVFC Blocker + Leak Return Val Not Used CPPCHECK_LRVNU Blocker + Memleak CPPCHECK_ML Blocker + Memleak On Realloc CPPCHECK_MOR Blocker + Mismatch Alloc Dealloc CPPCHECK_MAD Blocker + Mismatch Size CPPCHECK_MS Blocker + NULL Pointer Dereference With Default Argument CPPCHECK_NPDWDA Critical + Null Pointer CPPCHECK_NP Blocker + Pointer Arithmetic With NULL CPPCHECK_PAWN Blocker + Public Allocation Error CPPCHECK_PAE Critical + Redundant NULL Pointer Check CPPCHECK_RNPC Critical + Resource Leak CPPCHECK_RL Blocker + Return Address Of Auto Variable CPPCHECK_RAOAV Blocker + Return Address Of Function Parameter CPPCHECK_RAOFP Blocker + Return Dangling Lifetime CPPCHECK_RDL Blocker + Return Local Variable CPPCHECK_RLV Blocker + Return Reference CPPCHECK_RF Blocker + Return Temp Reference CPPCHECK_RTF Blocker + Unsafe Class Can Leak CPPCHECK_UCCL Minor + Unsafe allocation CPPCHECK_UA Critical + Useless Assignment Arg CPPCHECK_UAA Minor + Useless Assignment Ptr Arg CPPCHECK_UAPARG Critical + Object Orientedness Rules Assignment Operator Should Be Left Unimplemented CPPCHECK_AOSBLU Minor + Copy Constructor And Eq Operator CPPCHECK_CCAEO Critical + Copy Ctor Pointer Copying CPPCHECK_CCPC Minor + Dupl Inherited Member CPPCHECK_DIM Critical + Function Const CPPCHECK_FC Minor + Function Static CPPCHECK_FS Major + Initializer List CPPCHECK_IL Minor + Malloc On Class Error CPPCHECK_MOCE Blocker + Malloc On Class Warning CPPCHECK_MOCW Critical + Memset Class CPPCHECK_MC Blocker + Memset Class Float CPPCHECK_MCF Minor + Memset Class Reference CPPCHECK_MCR Blocker + Missing Return From Assignement Operator CPPCHECK_MRFAO Blocker + No Assignment Operator CPPCHECK_NAO Minor + No Constructor CPPCHECK_NC Minor + No Copy Constructor CPPCHECK_NCC Minor + No Destructor CPPCHECK_ND Minor + No Explicit Constructor CPPCHECK_NEC Minor + Operator Eq CPPCHECK_OE Minor + Operator Eq Ret Ref This CPPCHECK_OERRT Minor + Operator Eq To Self CPPCHECK_OETS Critical + Operator Eq Var Error CPPCHECK_OEVE Critical + Pure Virtual Call CPPCHECK_PVC Critical + Self Initialization CPPCHECK_SI Blocker + This Subtraction CPPCHECK_TS Critical + Uninitialized Member Variable CPPCHECK_UMV Critical + Unused Private Function CPPCHECK_UPF Minor + Use Initialization List CPPCHECK_UIL Major + Virtual Call In Constructor CPPCHECK_VCIC Critical + Virtual Destructor CPPCHECK_VD Blocker + Performance Rules Assign Bool To Float CPPCHECK_ABTF Minor + Passed By Value CPPCHECK_PBV Major + Postfix Operator CPPCHECK_PO Major + Redundant Assignment CPPCHECK_RA Minor + Redundant Copy CPPCHECK_RCPY Major + Redundant Copy Local Const CPPCHECK_RCLC Major + Same Iterator Expression CPPCHECK_SIE Minor + Portability Rules Assignment Address To Integer CPPCHECK_AATI Minor + Assignment Integer To Address CPPCHECK_AITA Minor + Cast Address To Integer At Return CPPCHECK_CATIAR Minor + Cast Integer To Address At Return CPPCHECK_CITAAR Minor + Readability and Consistency Rules Clarify Calculation CPPCHECK_CCALC Minor + Clarify Statement CPPCHECK_CSTAT Critical + Comma Separated Return CPPCHECK_CSR Minor + Cstyle Cast CPPCHECK_CSC Minor + Function Argument Names Different CPPCHECK_FAND Minor + Function Argument Order Different CPPCHECK_FAOD Critical + Missing Override CPPCHECK_MO Minor + Shadow Function CPPCHECK_SF Minor + Shadow Variable CPPCHECK_SV Minor + Suspicious Semicolon CPPCHECK_SS Critical + Variable Scope CPPCHECK_VS Minor + STL Rules Comparing Iterators Of Different Containers1 CPPCHECK_CIODC1 Blocker + Comparing Iterators Of Different Containers2 CPPCHECK_CIODC2 Blocker + Container Out Of Bounds CPPCHECK_COOB Blocker + Deref Invalid Iterator CPPCHECK_DII Critical + Erase Dereference CPPCHECK_ED Blocker + Invalid Iterator1 CPPCHECK_IIT Blocker + Invalid Iterator2 CPPCHECK_IIT2 Blocker + Invalid Pointer CPPCHECK_IP Blocker + Mismatching Containers CPPCHECK_MMC Blocker + Read Empty Container CPPCHECK_REC Minor + Redundant If Remove CPPCHECK_RIR Minor + Same Iterator With Different Containers1 CPPCHECK_SIWDC1 Blocker + Same Iterator With Different Containers2 CPPCHECK_SIWDC2 Blocker + Stl Boundaries CPPCHECK_STLB Blocker + Stl If Find CPPCHECK_STLIF Critical + Stl If Str Find CPPCHECK_STLISF Major + Stl Missing Comparison CPPCHECK_STLMC Critical + Stl Out Of Bounds CPPCHECK_STLOOB Blocker + Stl Size CPPCHECK_STLS Major + Stlcstr CPPCHECK_STLC Blocker + Stlcstr Param CPPCHECK_SCP Major + Stlcstr Return CPPCHECK_SCR Major + Stlcstr Throw CPPCHECK_SCT Blocker + Use Auto Pointer Array CPPCHECK_UAPA Blocker + Use Auto Pointer Container CPPCHECK_UAPC Blocker + Use Auto Pointer Copy CPPCHECK_UAPCPY Minor + Use Auto Pointer Malloc CPPCHECK_UAPM Blocker + Use STL Algorithm CPPCHECK_USA Minor + Useless Calls Compare CPPCHECK_UCC Critical + Useless Calls Empty CPPCHECK_UCE Critical + Useless Calls Remove CPPCHECK_UCR Critical + Useless Calls Substr CPPCHECK_UCSS Major + Useless Calls Swap CPPCHECK_UCS Major + Side Effect Rules Assert With Side Effect CPPCHECK_AWSE Critical + Assignment In Assert CPPCHECK_AIA Critical + Unknown Evaluation Order CPPCHECK_UEO Blocker + Simple Type Rules Assign Bool To Pointer CPPCHECK_ABTP Blocker + Bitwise On Boolean CPPCHECK_BOB Minor + Char Bit Op CPPCHECK_CBO Critical + Char Literal With Char Ptr Compare CPPCHECK_CLWCPC Critical + Character Array Index CPPCHECK_CAI Minor + Check Cast Int To Char And Back CPPCHECK_CCITCAB Critical + Compare Bool Expression With Int CPPCHECK_CBEWI Critical + Comparison Of Bool With Bool Error CPPCHECK_COBWBE Minor + Comparison Of Func Returning Bool Error CPPCHECK_COFRBE Minor + Comparison Of Two Funcs Returning Bool Error CPPCHECK_COTFRBE Minor + Float Conversion Overflow CPPCHECK_FCO Blocker + Incorrect Char Boolean Error CPPCHECK_ICBE Critical + Incorrect String Boolean Error CPPCHECK_ISBE Critical + Incorrect String Compare CPPCHECK_ISC Critical + Increment Boolean CPPCHECK_IB Minor + Integer Overflow CPPCHECK_IO Blocker + Invalid Pointer Cast CPPCHECK_IPC Minor + Memset Float CPPCHECK_MF Minor + Pointer Arith Bool CPPCHECK_PAB Blocker + Pointer Less Than Zero CPPCHECK_PLTZ Minor + Pointer Positive CPPCHECK_PP Minor + Shift By Negative CPPCHECK_SBN Blocker + Shift Negative CPPCHECK_SN Minor + Shift Too Many Bits CPPCHECK_STMB Blocker + Shift Too Many Bits Signed CPPCHECK_STMBS Blocker + Sign Conversion CPPCHECK_SC Critical + Signed Char Array Index CPPCHECK_SCAI Critical + Sprintf Overlapping Data CPPCHECK_SOD Blocker + Static String Compare CPPCHECK_SSC Critical + Str Plus Char CPPCHECK_SPC Blocker + String Compare CPPCHECK_STRCMP Critical + String Literal Write CPPCHECK_SLW Blocker + Trunc Long Cast Assignment CPPCHECK_TLCA Minor + Trunc Long Cast Return CPPCHECK_TLCR Minor + Unsigned Less Than Zero CPPCHECK_ULTZ Minor + Unsigned Positive CPPCHECK_UP Minor + Variable Comparison With String Literal CPPCHECK_VCWSL Critical + Sizeof Operator Rules Arithmetic Operations On Void Pointer CPPCHECK_AOOVP Minor + Divide Sizeof CPPCHECK_DSO Critical + Multiply Sizeof CPPCHECK_MSO Critical + Pointer Size CPPCHECK_PS Critical + Sizeof Calculation CPPCHECK_SOC Critical + Sizeof Dereferenced Void Pointer CPPCHECK_SODVP Minor + Sizeof Division Memfunc CPPCHECK_SODMF Critical + Sizeof Function Call CPPCHECK_SOFC Critical + Sizeof Sizeof CPPCHECK_SOSO Critical + Sizeof Void CPPCHECK_SOV Minor + Sizeof With Numeric Parameter CPPCHECK_SOWNP Critical + Sizeof With Silent Array Pointer CPPCHECK_SOWSAP Critical + Suspicious Construct Rules Const Statement CPPCHECK_CS Critical + Duplicate Assign Expression CPPCHECK_DAE Minor + Duplicate Branch CPPCHECK_DBRANCH Minor + Duplicate Expression CPPCHECK_DEXPR Minor + Duplicate Expression Ternary CPPCHECK_DET Minor + Duplicate Value Ternary CPPCHECK_DVT Minor + Mismatching Container Expression CPPCHECK_MCE Critical + Nan In Arithmetic Expression CPPCHECK_NIAE Minor + Opposite Expression CPPCHECK_OPE Minor + Overlapping Strcmp CPPCHECK_OS Critical + Redundant Assign In Switch CPPCHECK_RAIS Critical + Redundant Bitwise Operation In Switch CPPCHECK_RBOIS Critical + Redundant Copy In Switch CPPCHECK_RCIS Critical + Redundant Pointer Operation CPPCHECK_RPO Minor + Return Address Of Auto Variable CPPCHECK_RNBIBF Minor + Self Assignment CPPCHECK_SA Critical + Suspicious Case CPPCHECK_SUSPC Critical + Suspicious Equality Comparison CPPCHECK_SEC Critical + Unused Scoped Object CPPCHECK_UUSO Minor + Unnecessary and Unused Code Rules Unassigned Variable CPPCHECK_UAV Minor + Unread Variable CPPCHECK_URV Minor + Unused Allocated Memory CPPCHECK_UUAM Minor + Unused Function CPPCHECK_UUF Minor + Unused Label CPPCHECK_UL Minor + Unused Struct Member CPPCHECK_UUSM Minor + Unused Switch Label CPPCHECK_USL Critical + Unused Variable CPPCHECK_UUV Minor + Unreachable Code Rules Duplicate Break CPPCHECK_DBREAK Minor + Unreachable Code CPPCHECK_URC Minor + Variable Argument Related Rules Va_end Missing CPPCHECK_VAEM Blocker + Va_list Used Before Started CPPCHECK_VALUBS Blocker + Va_start Reference Passed CPPCHECK_VASRP Blocker + Va_start Subsequent Calls CPPCHECK_VASSC Blocker + Va_start Wrong Parameter CPPCHECK_VASWP Critical + Var Func Null UB CPPCHECK_VFNUB Minor + +### API Rules + +#### Invalid Function Argument Boolean {#CPPCHECK_IFAB} +Invalid func_name() argument nr 1. A non-boolean value is required. + +#### Invalid Function Argument String {#CPPCHECK_IFAS} +Invalid func_name() argument nr 1. A nul-terminated string is required. + +#### Invalid Function Arguments {#CPPCHECK_IFA} +Invalid func_name() argument nr 1. The value is 0 or 1 (boolean) but the valid values are '1:4'. + +#### Invalid Length Modifier Error {#CPPCHECK_ILME} +'I' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier. + +#### Memset Value Out Of Range {#CPPCHECK_MVOOR} +The 2nd memset() argument 'varname' doesn't fit into an 'unsigned char'. The 2nd parameter is passed as an 'int', but the function fills the block of memory using the 'unsigned char' conversion of this value. + +#### Memset Zero Bytes {#CPPCHECK_MZB} +memset() called to fill 0 bytes. The second and third arguments might be inverted. +The function memset ( void \* ptr, int value, size_t num ) sets the first num bytes of the block of memory pointed by ptr to the specified value. + +#### Race After Interlocked Decrement {#CPPCHECK_RAID} +Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead. + +#### Strncat Usage {#CPPCHECK_STRCU} +At most, strncat appends the 3rd parameter's amount of characters and adds a terminating null byte. The safe way to use strncat is to subtract one from the remaining space in the buffer and use it as 3rd parameter. + +Source: + +Source: + +#### Unprecise Math Call {#CPPCHECK_UPMC} +Expression '1 - erf(x)' can be replaced by 'erfc(x)' to avoid loss of precision. + +#### Wrong Math Call {#CPPCHECK_WMC} +Passing value '\#' to \#() leads to implementation-defined result. + +#### Wrong Pipe Parameter Size {#CPPCHECK_WPPS} +The pipe()/pipe2() system command takes an argument, which is an array of exactly two integers. The variable 'varname' is an array of size dimension, which does not match. + +### Boost Library Rules + +#### Boost Foreach Error {#CPPCHECK_BFE} +BOOST_FOREACH caches the end() iterator. It's undefined behavior if you modify the container inside. + +### Buffer Overrun Rules + +#### Argument Size {#CPPCHECK_AS} +The array 'array' is too small, the function 'function' expects a bigger one. + +#### Array Index Out Of Bounds {#CPPCHECK_AIOOB} +Array 'array[2]' index array[1][1] out of bounds. + +#### Array Index Out Of Bounds Cond {#CPPCHECK_AIOOBC} +Array 'x\[10\]' accessed at index 20, which is out of bounds. Otherwise condition 'y==20' is redundant. + +#### Array Index Then Check {#CPPCHECK_AITC} +Defensive programming: The variable 'index' is used as an array index before it is checked that is within limits. This can mean that the array might be accessed out of bounds. +Reorder conditions such as '(a\[i\] && i \< 10)' to '(i \< 10 && a\[i\])'. That way the array will not be accessed if the index is out of limits. + +#### Buffer Access Out Of Bounds {#CPPCHECK_BAOOB} +Buffer is accessed out of bounds: buffer + +#### Buffer Not Zero Terminated {#CPPCHECK_BNZT} +The buffer 'buffer' is not null-terminated after the call to strncpy(). This will cause bugs later in the code if the code assumes the buffer is null-terminated. + +#### Insecure Cmd Line Arguments {#CPPCHECK_ICLA} +Buffer overrun possible for long command line arguments. + +#### Negative Array Size {#CPPCHECK_NAS} +Declaration of array '' with negative size is undefined behaviour + +#### Negative Index {#CPPCHECK_NI} +Array index -1 is out of bounds. + +#### Negative Memory Allocation Size {#CPPCHECK_NMAS} +Memory allocation size is negative.Negative allocation size has no specified behaviour. + +#### Out Of Bounds {#CPPCHECK_OOB} +Index is out of bounds: Supplied size 2 is larger than actual size 1. + +#### Pointer Out Of Bounds {#CPPCHECK_POOB} +Undefined behaviour, pointer arithmetic '' is out of bounds. From chapter 6.5.6 in the C specification: "When an expression that has integer type is added to or subtracted from a pointer, .." and then "If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined." + +#### Possible Buffer Access Out Of Bounds {#CPPCHECK_PBAOOB} +Possible buffer overflow if strlen(source) is larger than or equal to sizeof(destination). The source buffer is larger than the destination buffer so there is the potential for overflowing the destination buffer. + +#### Size Argument As Char {#CPPCHECK_SAAC} +The size argument is given as a char constant. + +#### Terminate Strncpy {#CPPCHECK_TSTRC} +The buffer 'buffer' may not be null-terminated after the call to strncpy(). If the source string's size fits or exceeds the given size, strncpy() does not add a zero at the end of the buffer. This causes bugs later in the code if the code assumes buffer is null-terminated. + +### Conditional Rules + +#### Assign If Error {#CPPCHECK_AIE} +Mismatching assignment and comparison, comparison '' is always false. + +#### Bad Bitmask Check {#CPPCHECK_BBC} +Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'? + +#### Clarify Condition {#CPPCHECK_CCOND} +Suspicious condition (assignment + comparison); Clarify expression with parentheses. + +#### Comparison Error {#CPPCHECK_CE} +The expression '(X & 0x6) == 0x1' is always false. Check carefully constants and operators used, these errors might be hard to spot sometimes. In case of complex expression it might help to split it to separate expressions. + +#### Comparison Function Is Always True Or False {#CPPCHECK_CFIATOF} +The function isless is designed to compare two variables. Calling this function with one variable (varName) for both parameters leads to a statement which is always false. + +#### Comparison Of Bool With Invalid Comparator {#CPPCHECK_COBWIC} +The result of the expression 'expression' is of type 'bool'. Comparing 'bool' value using relational (<, >, <= or >=) operator could cause unexpected results. + +#### Condition is Always False {#CPPCHECK_CAF} +Condition 'x' is always false + +#### Identical Condition After Early Exit {#CPPCHECK_ICAEE} +Identical condition 'x', second condition is always false + +#### Identical Inner Condition {#CPPCHECK_IIC} +Identical inner 'if' condition is always true (outer condition is 'x' and inner condition is 'x'). + +#### Incorrect Logic Operator {#CPPCHECK_ILO} +Logical disjunction always evaluates to true: foo > 3 && foo \< 4. Are these conditions necessary? Did you intend to use && instead? Are the numbers correct? Are you comparing the correct variables? + +#### Invalid Test For Overflow {#CPPCHECK_ITFO} +Invalid test for overflow 'x + u < x'. Condition is always false unless there is overflow, and overflow is undefined behaviour. + +#### Mismatching Bit And {#CPPCHECK_MBA} +Mismatching bitmasks. Result is always 0 (X = Y & 0xf0; Z = X & 0x1; => Z=0). + +#### Modulo Always True False {#CPPCHECK_MATF} +Comparison of modulo result is predetermined, because it is always less than 1. + +#### Multi Condition {#CPPCHECK_MCOND} +Expression is always false because 'else if' condition matches previous condition at line 1. + +#### Opposite Inner Condition {#CPPCHECK_OIC} +Opposite inner 'if' condition leads to a dead code block (outer condition is 'x' and inner condition is '!x'). + +#### Pointer Addition Null Check {#CPPCHECK_PANC} +Comparison is wrong. Result of 'ptr+1' can't be 0 unless there is pointer overflow, and pointer overflow is undefined behaviour. + +#### Redundant Condition {#CPPCHECK_RCOND} +Redundant condition: If x > 11 the condition x > 10 is always true. + +### Division Rules + +#### Unsafe Class Can Divide By Zero {#CPPCHECK_UCCDBZ} +Public interface of Class is not safe. When calling Class::dostuff(), if parameter x is 0 that leads to division by zero. + +#### Zerodiv {#CPPCHECK_ZD} +Division by zero. + +#### Zerodivcond {#CPPCHECK_ZDC} +Either the condition is redundant or there is division by zero. + +### Exception Rules + +#### Catch Exception By Value {#CPPCHECK_CEBV} +The exception is caught by value. It could be caught as a (const) reference which is usually recommended in C++. + +#### Except Dealloc Throw {#CPPCHECK_EDT} +Exception thrown in invalid state, 'p' points at deallocated memory. + +#### Except Rethrow Copy {#CPPCHECK_ERC} +Rethrowing an exception with 'throw varname;' creates an unnecessary copy of 'varname'. To rethrow the caught exception without unnecessary copying or slicing, use a bare 'throw;'. + +#### Except Throw In Destructor {#CPPCHECK_ETID} +The class Class is not safe because its destructor throws an exception. If Class is used and an exception is thrown that is caught in an outer scope the program will terminate. + +#### Throw In Noexcept Function {#CPPCHECK_TINF} +Exception thrown in function declared not to throw exceptions. + +#### Unhandled Exception Specification {#CPPCHECK_UES} +Unhandled exception specification when calling function foo(). Either use a try/catch around the function call, or add a exception specification for funcname() also. + +### Initialization Rules + +#### Dangerous Use Of Strncpy {#CPPCHECK_DUOS} +Dangerous usage of 'varname' (strncpy doesn't always null-terminate it). + +#### Deadpointer {#CPPCHECK_DP} +Dead pointer usage. Pointer 'pointer' is dead if it has been assigned '&x' at line 0. + +#### Uninit Struct Member {#CPPCHECK_UISM} +Uninitialized struct member: a.b + +#### Uninitialized Data {#CPPCHECK_UID} +Memory is allocated but not initialized: varname + +#### Uninitialized Variable {#CPPCHECK_UIV} +Uninitialized variable: varname + +### Input Output Rules + +#### Cout Cerr Misusage {#CPPCHECK_CCM} +Invalid usage of output stream: '\<\< std::cout'. + +#### Fflush On Input Stream {#CPPCHECK_FOIS} +fflush() called on input stream 'stdin' may result in undefined behaviour on non-linux systems. + +#### IO Without Positioning {#CPPCHECK_IOWP} +Read and write operations without a call to a positioning function (fseek, fsetpos or rewind) or fflush in between result in undefined behaviour. + +#### Invalid Printf Arg Type_float {#CPPCHECK_IPATF} +%f in format string (no. 1) requires 'double' but the argument type is Unknown. + +#### Invalid Printf Arg Type_n {#CPPCHECK_IPATN} +%n in format string (no. 1) requires 'int \*' but the argument type is Unknown. + +#### Invalid Printf Arg Type_p {#CPPCHECK_IPATP} +%p in format string (no. 1) requires an address but the argument type is Unknown. + +#### Invalid Printf Arg Type_s {#CPPCHECK_IPATS} +%s in format string (no. 1) requires 'char \*' but the argument type is Unknown. + +#### Invalid Printf Arg Type_sint {#CPPCHECK_IPATSI} +%i in format string (no. 1) requires 'int' but the argument type is Unknown. + +#### Invalid Printf Arg Type_uint {#CPPCHECK_IPATUI} +%u in format string (no. 1) requires 'unsigned int' but the argument type is Unknown. + +#### Invalid Scanf {#CPPCHECK_IS} +scanf() without field width limits can crash with huge input data. Add a field width specifier to fix this problem. + +Sample program that can crash: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.cpp} +#include +int main() +{ + char c[5]; + scanf("%s", c); + return 0; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Typing in 5 or more characters may make the program crash. The correct usage here is 'scanf("%4s", c);', as the maximum field width does not include the terminating null byte. + +Source: + +Source: + +#### Invalid Scanf Arg Type_float {#CPPCHECK_ISATF} +%f in format string (no. 1) requires 'float \*' but the argument type is Unknown. + +#### Invalid Scanf Arg Type_int {#CPPCHECK_ISATI} +%d in format string (no. 1) requires 'int \*' but the argument type is Unknown. + +#### Invalid Scanf Arg Type_s {#CPPCHECK_ISATS} +%s in format string (no. 1) requires a 'char \*' but the argument type is Unknown. + +#### Invalid Scanf Format Width {#CPPCHECK_ISFW} +Width 5 given in format string (no. 10) is larger than destination buffer '\[0\]', use %-1s to prevent overflowing it. + +#### Read Write Only File {#CPPCHECK_RWOF} +Read operation on a file that was opened only for writing. + +#### Seek On Appended File {#CPPCHECK_SOAF} +Repositioning operation performed on a file opened in append mode has no effect. + +#### Use Closed File {#CPPCHECK_UCF} +Used file that is not opened. + +#### Write Read Only File {#CPPCHECK_WROF} +Write operation on a file that was opened only for reading. + +#### Wrong Printf Scanf Arg Num {#CPPCHECK_WPSAN} +printf format string requires 3 parameters but only 2 are given. + +#### Wrong Printf Scanf Parameter Position Error {#CPPCHECK_WPSPPE} +printf: referencing parameter 2 while 1 arguments given + +### Memory Handling Rules + +#### Access Forwarded {#CPPCHECK_AF} +Access of forwarded variable 'v'. + +#### Access Moved {#CPPCHECK_AM} +Access of moved variable 'v'. + +#### Auto Variables {#CPPCHECK_AV} +Dangerous assignment - the function parameter is assigned the address of a local auto-variable. Local auto-variables are reserved from the stack which is freed when the function ends. So the pointer to a local variable is invalid after the function ends. + +#### Auto Variables Assign Global Pointer {#CPPCHECK_AVAGP} +Address of local array array is assigned to global pointer pointer and not reassigned before array goes out of scope. + +#### Autovar Invalid Deallocation {#CPPCHECK_AID} +The deallocation of an auto-variable results in undefined behaviour. You should only free memory that has been allocated dynamically. + +#### Dangling Lifetime {#CPPCHECK_DL} +Non-local variable 'x' will use object. + +#### Dealloc Dealloc {#CPPCHECK_DD} +Deallocating a deallocated pointer: varname + +#### Deallocret {#CPPCHECK_DAR} +Returning/dereferencing 'p' after it is deallocated / released + +#### Deallocuse {#CPPCHECK_DU} +Dereferencing 'varname' after it is deallocated / released + +#### Double Free {#CPPCHECK_DF} +Memory pointed to by 'varname' is freed twice. + +#### Ignored Return Value {#CPPCHECK_IRV} +Return value of function malloc() is not used. + +#### Incomplete Array Fill {#CPPCHECK_IAF} +The array 'buffer' is filled incompletely. The function 'memset()' needs the size given in bytes, but an element of the given array is larger than one byte. Did you forget to multiply the size with 'sizeof(\*buffer)'? + +#### Invalid Free {#CPPCHECK_IF} +Invalid memory address freed. + +#### Invalid Lifetime {#CPPCHECK_ILT} +Using object that is out of scope. + +#### Leak No Var Function Call {#CPPCHECK_LNVFC} +Allocation with funcName, funcName doesn't release it. + +#### Leak Return Val Not Used {#CPPCHECK_LRVNU} +Return value of allocation function 'funcName' is not stored. + +#### Memleak {#CPPCHECK_ML} +Memory leak: varname + +#### Memleak On Realloc {#CPPCHECK_MOR} +Common realloc mistake: 'varname' nulled but not freed upon failure + +#### Mismatch Alloc Dealloc {#CPPCHECK_MAD} +Mismatching allocation and deallocation: varname + +#### Mismatch Size {#CPPCHECK_MS} +The allocated size sz is not a multiple of the underlying type's size. + +#### NULL Pointer Dereference With Default Argument {#CPPCHECK_NPDWDA} +Possible null pointer dereference if the default parameter value is used: pointer + +#### Null Pointer {#CPPCHECK_NP} +Null pointer dereference + +#### Pointer Arithmetic With NULL {#CPPCHECK_PAWN} +Pointer arithmetic with NULL pointer. + +#### Public Allocation Error {#CPPCHECK_PAE} +Possible leak in public function. The pointer 'varname' is not deallocated before it is allocated. + +#### Redundant NULL Pointer Check {#CPPCHECK_RNPC} +Either the condition is redundant or there is possible null pointer dereference: pointer. + +#### Resource Leak {#CPPCHECK_RL} +Resource leak: varname + +#### Return Address Of Auto Variable {#CPPCHECK_RAOAV} +Address of an auto-variable returned. + +#### Return Address Of Function Parameter {#CPPCHECK_RAOFP} +Address of the function parameter 'parameter' becomes invalid after the function exits because function parameters are stored on the stack which is freed when the function exits. Thus the returned value is invalid. + +#### Return Dangling Lifetime {#CPPCHECK_RDL} +Returning object that will be invalid when returning. + +#### Return Local Variable {#CPPCHECK_RLV} +Pointer to local array variable returned. + +#### Return Reference {#CPPCHECK_RF} +Reference to auto variable returned. + +#### Return Temp Reference {#CPPCHECK_RTF} +Reference to temporary returned. + +#### Unsafe Class Can Leak {#CPPCHECK_UCCL} +The class 'class' is unsafe, wrong usage can cause memory/resource leaks for 'class::varname'. This can for instance be fixed by adding proper cleanup in the destructor. + +#### Unsafe allocation {#CPPCHECK_UA} +Unsafe allocation. If funcName() throws, memory could be leaked. Use make_shared() instead. + +#### Useless Assignment Arg {#CPPCHECK_UAA} +Assignment of function parameter has no effect outside the function. + +#### Useless Assignment Ptr Arg {#CPPCHECK_UAPARG} +Assignment of function parameter has no effect outside the function. Did you forget dereferencing it? + +### Object Orientedness Rules + +#### Assignment Operator Should Be Left Unimplemented {#CPPCHECK_AOSBLU} +'operator=' should either return reference to 'this' instance or be declared private and left unimplemented. + +#### Copy Constructor And Eq Operator {#CPPCHECK_CCAEO} +The class 'class' has 'operator=' but lack of 'copy constructor'. + +#### Copy Ctor Pointer Copying {#CPPCHECK_CCPC} +Value of pointer 'var', which points to allocated memory, is copied in copy constructor instead of allocating new memory. + +#### Dupl Inherited Member {#CPPCHECK_DIM} +The class 'class' defines member variable with name 'variable' also defined in its parent class 'class'. + +#### Function Const {#CPPCHECK_FC} +The member function 'class::function' can be made a const function. Making this function 'const' should not cause compiler errors. Even though the function can be made const function technically it may not make sense conceptually. Think about your design and the task of the function first - is it a function that must not change object internal state? + +#### Function Static {#CPPCHECK_FS} +The member function 'class::function' can be made a static function. Making a function static can bring a performance benefit since no 'this' instance is passed to the function. This change should not cause compiler errors but it does not necessarily make sense conceptually. Think about your design and the task of the function first - is it a function that must not access members of class instances? And maybe it is more appropriate to move this function to a unnamed namespace. + +#### Initializer List {#CPPCHECK_IL} +Member variable 'class::variable' is in the wrong place in the initializer list. Members are initialized in the order they are declared, not in the order they are in the initializer list. Keeping the initializer list in the same order that the members were declared prevents order dependent initialization errors. + +#### Malloc On Class Error {#CPPCHECK_MOCE} +Memory for class instance allocated with malloc(), but class a std::string. This is unsafe, since no constructor is called and class members remain uninitialized. Consider using 'new' instead. + +#### Malloc On Class Warning {#CPPCHECK_MOCW} +Memory for class instance allocated with malloc(), but class provides constructors. This is unsafe, since no constructor is called and class members remain uninitialized. Consider using 'new' instead. + +#### Memset Class {#CPPCHECK_MC} +Using 'memfunc' on class that contains a classname is unsafe, because constructor, destructor and copy operator calls are omitted. These are necessary for this non-POD type to ensure that a valid object is created. + +#### Memset Class Float {#CPPCHECK_MCF} +Using memset() on class which contains a floating point number. This is not portable because memset() sets each byte of a block of memory to a specific value and the actual representation of a floating-point value is implementation defined. + +Note: In case of an IEEE754-1985 compatible implementation setting all bits to zero results in the value 0.0. + +#### Memset Class Reference {#CPPCHECK_MCR} +Using 'memfunc' on class that contains a reference. + +#### Missing Return From Assignement Operator {#CPPCHECK_MRFAO} +No 'return' statement in non-void function causes undefined behavior. + +#### No Assignment Operator {#CPPCHECK_NAO} +Class 'class' does not have a operator= which is recommended since it has dynamic memory/resource allocation(s). + +#### No Constructor {#CPPCHECK_NC} +The class 'classname' does not have a constructor although it has private member variables. Member variables of builtin types are left uninitialized when the class is instantiated. That may cause bugs or undefined behavior. + +#### No Copy Constructor {#CPPCHECK_NCC} +Class 'class' does not have a copy constructor which is recommended since it has dynamic memory/resource allocation(s). + +#### No Destructor {#CPPCHECK_ND} +Class 'class' does not have a destructor which is recommended since it has dynamic memory/resource allocation(s). + +#### No Explicit Constructor {#CPPCHECK_NEC} +Class 'classname' has a constructor with 1 argument that is not explicit. Such constructors should in general be explicit for type safety reasons. Using the explicit keyword in the constructor means some mistakes when using the class can be avoided. + +#### Operator Eq {#CPPCHECK_OE} +The class::operator= does not conform to standard C/C++ behaviour. To conform to standard C/C++ behaviour, return a reference to self (such as: 'class &class::operator=(..) { .. return *this; }'. For safety reasons it might be better to not fix this message. If you think that safety is always more important than conformance then please ignore/suppress this message. For more details about this topic, see the book "Effective C++" by Scott Meyers. + +#### Operator Eq Ret Ref This {#CPPCHECK_OERRT} +'operator=' should return reference to 'this' instance. + +#### Operator Eq To Self {#CPPCHECK_OETS} +'operator=' should check for assignment to self to ensure that each block of dynamically allocated memory is owned and managed by only one instance of the class. + +#### Operator Eq Var Error {#CPPCHECK_OEVE} +Member variable 'classname::' is not assigned a value in 'classname::operator='. + +#### Pure Virtual Call {#CPPCHECK_PVC} +Call of pure virtual function 'f' in constructor. The call will fail during runtime. + +#### Self Initialization {#CPPCHECK_SI} +Member variable 'var' is initialized by itself. + +#### This Subtraction {#CPPCHECK_TS} +Suspicious pointer subtraction. Did you intend to write '->'? + +#### Uninitialized Member Variable {#CPPCHECK_UMV} +Member variable 'classname::varname' is not initialized in the constructor. + +#### Unused Private Function {#CPPCHECK_UPF} +Unused private function: 'classname::funcname' + +#### Use Initialization List {#CPPCHECK_UIL} +When an object of a class is created, the constructors of all member variables are called consecutively in the order the variables are declared, even if you don't explicitly write them to the initialization list. You could avoid assigning 'variable' a value by passing the value to the constructor in the initialization list. + +#### Virtual Call In Constructor {#CPPCHECK_VCIC} +Virtual function 'f' is called from constructor '' at line 1. Dynamic binding is not used. + +#### Virtual Destructor {#CPPCHECK_VD} +Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. If you destroy instances of the derived class by deleting a pointer that points to the base class, only the destructor of the base class is executed. Thus, dynamic memory that is managed by the derived class could leak. This can be avoided by adding a virtual destructor to the base class. + +### Performance Rules + +#### Assign Bool To Float {#CPPCHECK_ABTF} +Boolean value assigned to floating point variable. + +#### Passed By Value {#CPPCHECK_PBV} +Parameter 'parametername' is passed by value. It could be passed as a const reference which is usually faster and recommended in C++. + +#### Postfix Operator {#CPPCHECK_PO} +Prefix ++/-- operators should be preferred for non-primitive types. Pre-increment/decrement can be more efficient than post-increment/decrement. Post-increment/decrement usually involves keeping a copy of the previous value around and adds a little extra code. + +#### Redundant Assignment {#CPPCHECK_RA} +Variable 'var' is reassigned a value before the old one has been used. + +#### Redundant Copy {#CPPCHECK_RCPY} +Buffer 'var' is being written before its old content has been used. + +#### Redundant Copy Local Const {#CPPCHECK_RCLC} +The const variable 'varname' is assigned a copy of the data. You can avoid the unnecessary data copying by converting 'varname' to const reference. + +#### Same Iterator Expression {#CPPCHECK_SIE} +Same iterators expression are used for algorithm. + +### Portability Rules + +#### Assignment Address To Integer {#CPPCHECK_AATI} +Assigning a pointer to an integer (int/long/etc) is not portable across different platforms and compilers. For example in 32-bit Windows and linux they are same width, but in 64-bit Windows and linux they are of different width. In worst case you end up assigning 64-bit address to 32-bit integer. The safe way is to store addresses only in pointer types (or typedefs like uintptr_t). + +#### Assignment Integer To Address {#CPPCHECK_AITA} +Assigning an integer (int/long/etc) to a pointer is not portable across different platforms and compilers. For example in 32-bit Windows and linux they are same width, but in 64-bit Windows and linux they are of different width. In worst case you end up assigning 64-bit integer to 32-bit pointer. The safe way is to store addresses only in pointer types (or typedefs like uintptr_t). + +#### Cast Address To Integer At Return {#CPPCHECK_CATIAR} +Returning an address value in a function with integer (int/long/etc) return type is not portable across different platforms and compilers. For example in 32-bit Windows and Linux they are same width, but in 64-bit Windows and Linux they are of different width. In worst case you end up casting 64-bit address down to 32-bit integer. The safe way is to always return an integer. + +#### Cast Integer To Address At Return {#CPPCHECK_CITAAR} +Returning an integer (int/long/etc) in a function with pointer return type is not portable across different platforms and compilers. For example in 32-bit Windows and Linux they are same width, but in 64-bit Windows and Linux they are of different width. In worst case you end up casting 64-bit integer down to 32-bit pointer. The safe way is to always return a pointer. + +### Readability and Consistency Rules + +#### Clarify Calculation {#CPPCHECK_CCALC} +Suspicious calculation. Please use parentheses to clarify the code. The code ''a+b?c:d'' should be written as either ''(a+b)?c:d'' or ''a+(b?c:d)''. + +#### Clarify Statement {#CPPCHECK_CSTAT} +A statement like '\*A++;' might not do what you intended. Postfix 'operator++' is executed before 'operator\*'. Thus, the dereference is meaningless. Did you intend to write '(\*A)++;'? + +#### Comma Separated Return {#CPPCHECK_CSR} +Comma is used in return statement. When comma is used in a return statement it can easily be misread as a semicolon. + +For example in the code below the value of 'b' is returned if the condition is true, but it is easy to think that 'a+1' is returned: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.cpp} + if (x) + return a + 1, + b++; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +However it can be useful to use comma in macros. Cppcheck does not warn when such a macro is then used in a return statement, it is less likely such code is misunderstood. + +#### Cstyle Cast {#CPPCHECK_CSC} +C-style pointer casting detected. C++ offers four different kinds of casts as replacements: static_cast, const_cast, dynamic_cast and reinterpret_cast. A C-style cast could evaluate to any of those automatically, thus it is considered safer if the programmer explicitly states which kind of cast is expected. + +See also: . + +#### Function Argument Names Different {#CPPCHECK_FAND} +Function 'function' argument 2 names different: declaration 'A' definition 'B'. + +#### Function Argument Order Different {#CPPCHECK_FAOD} +Function 'function' argument order different: declaration '' definition '' + +#### Missing Override {#CPPCHECK_MO} +The function '' overrides a function in a base class but is not marked with a 'override' specifier. + +#### Shadow Function {#CPPCHECK_SF} +Local variable f shadows outer function + +#### Shadow Variable {#CPPCHECK_SV} +Local variable var shadows outer variable + +#### Suspicious Semicolon {#CPPCHECK_SS} +Suspicious use of ; at the end of '' statement. + +#### Variable Scope {#CPPCHECK_VS} +The scope of the variable 'varname' can be reduced. Warning: Be careful when fixing this message, especially when there are inner loops. + +Here is an example where cppcheck will write that the scope for 'i' can be reduced: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.cpp} +void f(int x) +{ + int i = 0; + if (x) { + // it's safe to move 'int i = 0;' here + for (int n = 0; n < 10; ++n) { + // it is possible but not safe to move 'int i = 0;' here + do_something(&i); + } + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When you see this message it is always safe to reduce the variable scope 1 level. + +### STL Rules + +#### Comparing Iterators Of Different Containers1 {#CPPCHECK_CIODC1} +Comparison of iterators from containers 'container1' and 'container2'. + +#### Comparing Iterators Of Different Containers2 {#CPPCHECK_CIODC2} +Comparison of iterators from containers 'container' that are defined in different scopes. + +#### Container Out Of Bounds {#CPPCHECK_COOB} +Out of bounds access of item in container 'var' + +#### Deref Invalid Iterator {#CPPCHECK_DII} +Possible dereference of an invalid iterator: i. Make sure to check that the iterator is valid before dereferencing it - not after. + +#### Erase Dereference {#CPPCHECK_ED} +The iterator 'iter' is invalid before being assigned. Dereferencing or comparing it with another iterator is invalid operation. + +#### Invalid Iterator1 {#CPPCHECK_IIT} +Invalid iterator: iterator + +#### Invalid Iterator2 {#CPPCHECK_IIT2} +After push_back|push_front|insert(), the iterator 'iterator' may be invalid. + +#### Invalid Pointer {#CPPCHECK_IP} +Invalid pointer 'pointer' after push_back(). + +#### Mismatching Containers {#CPPCHECK_MMC} +Iterators of different containers are used together. + +#### Read Empty Container {#CPPCHECK_REC} +Reading from empty STL container 'var' + +#### Redundant If Remove {#CPPCHECK_RIR} +Redundant checking of STL container element existence before removing it. It is safe to call the remove method on a non-existing element. + +#### Same Iterator With Different Containers1 {#CPPCHECK_SIWDC1} +Same iterator is used with different containers 'container1' and 'container2'. + +#### Same Iterator With Different Containers2 {#CPPCHECK_SIWDC2} +Same iterator is used with containers 'container' that are defined in different scopes. + +#### Stl Boundaries {#CPPCHECK_STLB} +Iterator compared with operator\<. This is dangerous since the order of items in the container is not guaranteed. One should use operator!= instead to compare iterators. + +#### Stl If Find {#CPPCHECK_STLIF} +Suspicious condition. The result of find() is an iterator, but it is not properly checked. + +#### Stl If Str Find {#CPPCHECK_STLISF} +Either inefficient or wrong usage of string::find(). string::compare() will be faster if string::find's result is compared with 0, because it will not scan the whole string. If your intention is to check that there are no findings in the string, you should compare with std::string::npos. + +#### Stl Missing Comparison {#CPPCHECK_STLMC} +The iterator incrementing is suspicious - it is incremented at line and then at line . The loop might unintentionally skip an element in the container. There is no comparison between these increments to prevent that the iterator is incremented beyond the end. + +#### Stl Out Of Bounds {#CPPCHECK_STLOOB} +When i==foo.size(), foo\[i\] is out of bounds. + +#### Stl Size {#CPPCHECK_STLS} +Checking for 'list' emptiness might be inefficient. Using list.empty() instead of list.size() can be faster. list.size() can take linear time but list.empty() is guaranteed to take constant time. + +#### Stlcstr {#CPPCHECK_STLC} +Dangerous usage of c_str(). The c_str() return value is only valid until its string is deleted. + +#### Stlcstr Param {#CPPCHECK_SCP} +The conversion from const char\* as returned by c_str() to std::string creates an unnecessary string copy. Solve that by directly passing the string. + +#### Stlcstr Return {#CPPCHECK_SCR} +The conversion from const char\* as returned by c_str() to std::string creates an unnecessary string copy. Solve that by directly returning the string. + +#### Stlcstr Throw {#CPPCHECK_SCT} +Dangerous usage of c_str(). The string is destroyed after the c_str() call so the thrown pointer is invalid. + +#### Use Auto Pointer Array {#CPPCHECK_UAPA} +Object pointed by an 'auto_ptr' is destroyed using operator 'delete'. This means that you should only use 'auto_ptr' for pointers obtained with operator 'new'. This excludes arrays, which are allocated by operator 'new\[\]' and must be deallocated by operator 'delete\[\]'. + +#### Use Auto Pointer Container {#CPPCHECK_UAPC} +An element of container must be able to be copied but 'auto_ptr' does not fulfill this requirement. You should consider to use 'shared_ptr' or 'unique_ptr'. It is suitable for use in containers, because they no longer copy their values, they move them. + +#### Use Auto Pointer Copy {#CPPCHECK_UAPCPY} +'std::auto_ptr' has semantics of strict ownership, meaning that the 'auto_ptr' instance is the sole entity responsible for the object's lifetime. If an 'auto_ptr' is copied, the source looses the reference. + +#### Use Auto Pointer Malloc {#CPPCHECK_UAPM} +Object pointed by an 'auto_ptr' is destroyed using operator 'delete'. You should not use 'auto_ptr' for pointers obtained with function 'malloc'. This means that you should only use 'auto_ptr' for pointers obtained with operator 'new'. This excludes use C library allocation functions (for example 'malloc'), which must be deallocated by the appropriate C library function. + +#### Use STL Algorithm {#CPPCHECK_USA} +Consider using algorithm instead of a raw loop. + +#### Useless Calls Compare {#CPPCHECK_UCC} +'std::string::find()' returns zero when given itself as parameter (str.find(str)). As it is currently the code is inefficient. It is possible either the string searched ('str') or searched for ('str') is wrong. + +#### Useless Calls Empty {#CPPCHECK_UCE} +Ineffective call of function 'empty()'. Did you intend to call 'clear()' instead? + +#### Useless Calls Remove {#CPPCHECK_UCR} +The return value of std::remove() is ignored. This function returns an iterator to the end of the range containing those elements that should be kept. Elements past new end remain valid but with unspecified values. Use the erase method of the container to delete them. + +#### Useless Calls Substr {#CPPCHECK_UCSS} +Ineffective call of function 'substr' because it returns a copy of the object. Use operator= instead. + +#### Useless Calls Swap {#CPPCHECK_UCS} +The 'swap()' function has no logical effect when given itself as parameter (str.swap(str)). As it is currently the code is inefficient. Is the object or the parameter wrong here? + +### Side Effect Rules + +#### Assert With Side Effect {#CPPCHECK_AWSE} +Non-pure function: 'function' is called inside assert statement. Assert statements are removed from release builds so the code inside assert statement is not executed. If the code is needed also in release builds, this is a bug. + +#### Assignment In Assert {#CPPCHECK_AIA} +Variable 'var' is modified insert assert statement. Assert statements are removed from release builds so the code inside assert statement is not executed. If the code is needed also in release builds, this is a bug. + +#### Unknown Evaluation Order {#CPPCHECK_UEO} +Expression 'x = x++;' depends on order of evaluation of side effects + +### Simple Type Rules + +#### Assign Bool To Pointer {#CPPCHECK_ABTP} +Boolean value assigned to pointer. + +#### Bitwise On Boolean {#CPPCHECK_BOB} +Boolean variable 'varname' is used in bitwise operation. Did you mean '&&'? + +#### Char Bit Op {#CPPCHECK_CBO} +When using 'char' variables in bit operations, sign extension can generate unexpected results. + +For example: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.cpp} +char c = 0x80; +int i = 0 | c; +if (i & 0x8000) + printf("not expected"); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The "not expected" will be printed on the screen. + +#### Char Literal With Char Ptr Compare {#CPPCHECK_CLWCPC} +Char literal compared with pointer 'foo'. Did you intend to dereference it? + +#### Character Array Index {#CPPCHECK_CAI} +'char' type used as array index. Values greater that 127 will be treated depending on whether 'char' is signed or unsigned on target platform. + +#### Check Cast Int To Char And Back {#CPPCHECK_CCITCAB} +When saving func_name() return value in char variable there is loss of precision. When func_name() returns EOF this value is truncated. Comparing the char variable with EOF can have unexpected results. For instance a loop "while (EOF != (c = func_name());" loops forever on some compilers/platforms and on other compilers/platforms it will stop when the file contains a matching character. + +#### Compare Bool Expression With Int {#CPPCHECK_CBEWI} +Comparison of a boolean expression with an integer other than 0 or 1. + +#### Comparison Of Bool With Bool Error {#CPPCHECK_COBWBE} +The variable 'var_name' is of type 'bool' and comparing 'bool' value using relational (\<, >, \<= or >=) operator could cause unexpected results. + +#### Comparison Of Func Returning Bool Error {#CPPCHECK_COFRBE} +The return type of function 'func_name' is 'bool' and result is of type 'bool'. Comparing 'bool' value using relational (\<, >, \<= or >=) operator could cause unexpected results. + +#### Comparison Of Two Funcs Returning Bool Error {#CPPCHECK_COTFRBE} +The return type of function 'func_name1' and function 'func_name2' is 'bool' and result is of type 'bool'. Comparing 'bool' value using relational (\<, >, \<= or >=) operator could cause unexpected results. + +#### Float Conversion Overflow {#CPPCHECK_FCO} +Undefined behaviour: float (1e+100) to integer conversion overflow. + +#### Incorrect Char Boolean Error {#CPPCHECK_ICBE} +Conversion of char literal 'x' to bool always evaluates to true. + +#### Incorrect String Boolean Error {#CPPCHECK_ISBE} +Conversion of string literal "Hello World" to bool always evaluates to true. + +#### Incorrect String Compare {#CPPCHECK_ISC} +String literal "Hello World" doesn't match length argument for substr(). + +#### String Literal Write {#CPPCHECK_SLW} +Modifying string literal directly or indirectly is undefined behaviour. + +#### Increment Boolean {#CPPCHECK_IB} +The operand of a postfix increment operator may be of type bool but it is deprecated by C++ Standard (Annex D-1) and the operand is always set to true. You should assign it the value 'true' instead. + +#### Integer Overflow {#CPPCHECK_IO} +Signed integer overflow for expression ''. + +#### Invalid Pointer Cast {#CPPCHECK_IPC} +Casting between float\* and double\* which have an incompatible binary data representation. + +#### Memset Float {#CPPCHECK_MF} +The 2nd memset() argument 'varname' is a float, its representation is implementation defined. memset() is used to set each byte of a block of memory to a specific value and the actual representation of a floating-point value is implementation defined. + +#### Pointer Arith Bool {#CPPCHECK_PAB} +Converting pointer arithmetic result to bool. The boolean result is always true unless there is pointer arithmetic overflow, and overflow is undefined behaviour. Probably a dereference is forgotten. + +#### Pointer Less Than Zero {#CPPCHECK_PLTZ} +A pointer can not be negative so it is either pointless or an error to check if it is. + +#### Pointer Positive {#CPPCHECK_PP} +A pointer can not be negative so it is either pointless or an error to check if it is not. + +#### Shift By Negative {#CPPCHECK_SBN} +Shifting by a negative value is undefined behaviour + +#### Shift Negative {#CPPCHECK_SN} +Shifting a negative value is technically undefined behaviour + +#### Shift Too Many Bits {#CPPCHECK_STMB} +Shifting 32-bit value by 40 bits is undefined behaviour + +#### Shift Too Many Bits Signed {#CPPCHECK_STMBS} +Shifting signed 32-bit value by 31 bits is undefined behaviour + +#### Sign Conversion {#CPPCHECK_SC} +Suspicious code: sign conversion of var in calculation, even though var can have a negative value + +#### Signed Char Array Index {#CPPCHECK_SCAI} +Signed 'char' type used as array index. If the value can be greater than 127 there will be a buffer underflow because of sign extension. + +#### Sprintf Overlapping Data {#CPPCHECK_SOD} +The variable 'varname' is used both as a parameter and as destination in s[n]printf(). The origin and destination buffers overlap. +Quote from glibc (C-library) documentation (): "If copying takes place between objects that overlap as a result of a call to sprintf() or snprintf(), the results are undefined." + +#### Static String Compare {#CPPCHECK_SSC} +The compared strings, 'str1' and 'str2', are always unequal. Therefore the comparison is unnecessary and looks suspicious. + +#### Str Plus Char {#CPPCHECK_SPC} +Unusual pointer arithmetic. A value of type 'char' is added to a string literal. + +#### String Compare {#CPPCHECK_STRCMP} +The compared strings, 'varname1' and 'varname2', are identical. This could be a logic bug. + +#### Trunc Long Cast Assignment {#CPPCHECK_TLCA} +int result is assigned to long variable. If the variable is long to avoid loss of information, then there is loss of information. To avoid loss of information you must cast a calculation operand to long, for example 'l = a \* b;' => 'l = (long)a \* b;'. + +#### Trunc Long Cast Return {#CPPCHECK_TLCR} +int result is returned as long value. If the return value is long to avoid loss of information, then there is loss of information. To avoid loss of information you must cast a calculation operand to long, for example 'return a\*b;' => 'return (long)a\*b'. + +#### Unsigned Less Than Zero {#CPPCHECK_ULTZ} +The unsigned variable 'varname' will never be negative so it is either pointless or an error to check if it is. + +#### Unsigned Positive {#CPPCHECK_UP} +Unsigned variable 'varname' can't be negative so it is unnecessary to test it. + +#### Variable Comparison With String Literal {#CPPCHECK_VCWSL} +String literal compared with variable 'foo'. Did you intend to use strcmp() instead? + +### Sizeof Operator Rules + +#### Arithmetic Operations On Void Pointer {#CPPCHECK_AOOVP} +'varname' is of type 'vartype'. When using void pointers in calculations, the behaviour is undefined. Arithmetic operations on 'void \*' is a GNU C extension, which defines the 'sizeof(void)' to be 1. + +#### Divide Sizeof {#CPPCHECK_DSO} +Division of result of sizeof() on pointer type. sizeof() returns the size of the pointer, not the size of the memory area it points to. + +#### Multiply Sizeof {#CPPCHECK_MSO} +Multiplying sizeof() with sizeof() indicates a logic error. + +#### Pointer Size {#CPPCHECK_PS} +Size of pointer 'varname' used instead of size of its data. This is likely to lead to a buffer overflow. You probably intend to write 'sizeof(\*varname)'. + +#### Sizeof Calculation {#CPPCHECK_SOC} +Found calculation inside sizeof(). + +#### Sizeof Dereferenced Void Pointer {#CPPCHECK_SODVP} +'\*varname' is of type 'void', the behaviour of 'sizeof(void)' is not covered by the ISO C standard. A value for 'sizeof(void)' is defined only as part of a GNU C extension, which defines 'sizeof(void)' to be 1. + +#### Sizeof Division Memfunc {#CPPCHECK_SODMF} +Division by result of sizeof(). memset() expects a size in bytes, did you intend to multiply instead? + +#### Sizeof Function Call {#CPPCHECK_SOFC} +Found function call inside sizeof(). + +#### Sizeof Sizeof {#CPPCHECK_SOSO} +Calling sizeof for 'sizeof looks like a suspicious code and most likely there should be just one 'sizeof'. The current code is equivalent to 'sizeof(size_t)' + +#### Sizeof Void {#CPPCHECK_SOV} +Behaviour of 'sizeof(void)' is not covered by the ISO C standard. A value for 'sizeof(void)' is defined only as part of a GNU C extension, which defines 'sizeof(void)' to be 1. + +#### Sizeof With Numeric Parameter {#CPPCHECK_SOWNP} +It is unusual to use a constant value with sizeof. For example, 'sizeof(10)' returns 4 (in 32-bit systems) or 8 (in 64-bit systems) instead of 10. 'sizeof('A')' and 'sizeof(char)' can return different results. + +#### Sizeof With Silent Array Pointer {#CPPCHECK_SOWSAP} +Using 'sizeof' for array given as function argument returns the size of a pointer. It does not return the size of the whole array in bytes as might be expected. + +For example, this code: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.cpp} +int f(char a[100]) { + return sizeof(a); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +returns 4 (in 32-bit systems) or 8 (in 64-bit systems) instead of 100 (the size of the array in bytes). + +### Suspicious Construct Rules + +#### Const Statement {#CPPCHECK_CS} +Redundant code: Found a statement that begins with type constant. + +#### Duplicate Assign Expression {#CPPCHECK_DAE} +Finding variables 'x' and 'x' that are assigned the same expression is suspicious and might indicate a cut and paste or logic error. Please examine this code carefully to determine if it is correct. + +#### Duplicate Branch {#CPPCHECK_DBRANCH} +Finding the same code in an 'if' and related 'else' branch is suspicious and might indicate a cut and paste or logic error. Please examine this code carefully to determine if it is correct. + +#### Duplicate Expression {#CPPCHECK_DEXPR} +Finding the same expression on both sides of an operator is suspicious and might indicate a cut and paste or logic error. Please examine this code carefully to determine if it is correct. + +#### Duplicate Expression Ternary {#CPPCHECK_DET} +Finding the same expression in both branches of ternary operator is suspicious as the same code is executed regardless of the condition. + +#### Duplicate Value Ternary {#CPPCHECK_DVT} +Finding the same value in both branches of ternary operator is suspicious as the same code is executed regardless of the condition. + +#### Mismatching Container Expression {#CPPCHECK_MCE} +Iterators to containers from different expressions 'v1' and 'v2' are used together. + +#### Nan In Arithmetic Expression {#CPPCHECK_NIAE} +Using NaN/Inf in a computation. Although nothing bad really happens, it is suspicious. + +#### Opposite Expression {#CPPCHECK_OPE} +Finding the opposite expression on both sides of an operator is suspicious and might indicate a cut and paste or logic error. Please examine this code carefully to determine if it is correct. + +#### Overlapping Strcmp {#CPPCHECK_OS} +The expression 'strcmp(x,"def") != 0' is suspicious. It overlaps 'strcmp(x,"abc") == 0'. + +#### Redundant Assign In Switch {#CPPCHECK_RAIS} +Variable 'var' is reassigned a value before the old one has been used. 'break;' missing? + +#### Redundant Bitwise Operation In Switch {#CPPCHECK_RBOIS} +Redundant bitwise operation on 'varname' in 'switch' statement. 'break;' missing? + +#### Redundant Copy In Switch {#CPPCHECK_RCIS} +Buffer 'var' is being written before its old content has been used. 'break;' missing? + +#### Redundant Pointer Operation {#CPPCHECK_RPO} +Redundant pointer operation on 'varname' - it's already a pointer. + +#### Return Address Of Auto Variable {#CPPCHECK_RNBIBF} +Non-boolean value returned from function returning bool + +#### Self Assignment {#CPPCHECK_SA} +Redundant assignment of 'varname' to itself. + +#### Suspicious Case {#CPPCHECK_SUSPC} +Using an operator like '||' in a case label is suspicious. Did you intend to use a bitwise operator, multiple case labels or if/else instead? + +#### Suspicious Equality Comparison {#CPPCHECK_SEC} +Found suspicious equality comparison. Did you intend to assign a value instead? + +#### Unused Scoped Object {#CPPCHECK_UUSO} +Instance of 'varname' object is destroyed immediately. + +### Unnecessary and Unused Code Rules + +#### Unassigned Variable {#CPPCHECK_UAV} +Variable 'varname' is not assigned a value. + +#### Unread Variable {#CPPCHECK_URV} +Variable 'varname' is assigned a value that is never used. + +#### Unused Allocated Memory {#CPPCHECK_UUAM} +Variable 'varname' is allocated memory that is never used. + +#### Unused Function {#CPPCHECK_UUF} +The function 'funcName' is never used. + +#### Unused Label {#CPPCHECK_UL} +Label '' is not used. + +#### Unused Struct Member {#CPPCHECK_UUSM} +struct member 'structname::variable' is never used. + +#### Unused Switch Label {#CPPCHECK_USL} +Label '' is not used. Should this be a 'case' of the enclosing switch()? + +#### Unused Variable {#CPPCHECK_UUV} +Unused variable: varname + +### Unreachable Code Rules + +#### Duplicate Break {#CPPCHECK_DBREAK} +Consecutive return, break, continue, goto or throw statements are unnecessary. The second statement can never be executed, and so should be removed. + +#### Unreachable Code {#CPPCHECK_URC} +Statements following return, break, continue, goto or throw will never be executed. + +### Variable Argument Related Rules + +#### Va_end Missing {#CPPCHECK_VAEM} +va_list 'vl' was opened but not closed by va_end(). + +#### Va_list Used Before Started {#CPPCHECK_VALUBS} +va_list 'vl' used before va_start() was called. + +#### Va_start Reference Passed {#CPPCHECK_VASRP} +Using reference 'arg1' as parameter for va_start() results in undefined behaviour. + +#### Va_start Subsequent Calls {#CPPCHECK_VASSC} +va_start() or va_copy() called subsequently on 'vl' without va_end() in between. + +#### Va_start Wrong Parameter {#CPPCHECK_VASWP} +'arg1' given to va_start() is not last named argument of the function. Did you intend to pass 'arg2'? + +#### Var Func Null UB {#CPPCHECK_VFNUB} +Passing NULL after the last typed argument to a variadic function leads to undefined behaviour. + +The C99 standard, in section 7.15.1.1, states that if the type used by va_arg() is not compatible with the type of the actual next argument (as promoted according to the default argument promotions), the behavior is undefined. +The value of the NULL macro is an implementation-defined null pointer constant (7.17), which can be any integer constant expression with the value 0, or such an expression casted to (void\*) (6.3.2.3). +This includes values like 0, 0L, or even 0LL. +In practice on common architectures, this will cause real crashes if sizeof(int) != sizeof(void\*), and NULL is defined to 0 or any other null pointer constant that promotes to int. +To reproduce you might be able to use this little code example on 64bit platforms. +If the output includes "ERROR", the sentinel had only 4 out of 8 bytes initialized to zero and was not detected as the final argument to stop argument processing via va_arg(). +Changing the 0 to (void\*)0 or 0L will make the "ERROR" output go away. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.cpp} +#include +#include + +void f(char *s, ...) { + va_list ap; + va_start(ap,s); + for (;;) { + char *p = va_arg(ap,char*); + printf("%018p, %s\n", p, (long)p & 255 ? p : ""); + if(!p) break; + } + va_end(ap); +} + +void g() { + char *s2 = "x"; + char *s3 = "ERROR"; + // changing 0 to 0L for the 7th argument (which is intended to act as sentinel) makes the error go away on x86_64 + f("first", s2, s2, s2, s2, s2, 0, s3, (char*)0); +} + +void h() + int i; + volatile unsigned char a[1000]; + for (i = 0; i + + + + + + + + + + + + + + + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**-runUDM** + + : This parameter turns on or off the UserDefinedMetrics module. With this feature, OpenStaticAnalyzer computes custom source code metrics based on other, previously computed metrics. Its value can be "true" (turn this feature on) or "false" (turn this feature off). The default value is dependent on the presence of custom metric definitions in the profile xml. + + +**-cloneGenealogy** + + : This parameter turns on or off the tracking of code clones (copy-pasted source code fragments) through the consecutive revisions of the software system. It is required that during the analysis of the different revisions, the values set to projectName and resultsDir remain the same, so OpenStaticAnalyzer will handle them as different revisions of the same system. Its value can be "true" (turn this feature on) or "false" (turn this feature off). The default value is "false". + +**-cloneMinLines** + + : This parameter sets the minimum required size of each duplication in lines of code. The default value is 10. + +**-csvSeparator** + + : This parameter sets the separator character in the CSV outputs. The default value is the comma (","). The character set here must be placed in quotation marks (e.g. -csvSeparator=";"). Tabulator character can be set by the special "\\t" value. + +**-csvDecimalMark** + + : This parameter sets the decimal mark character in the CSV outputs. The default is value is the dot ("."). The character set here must be placed in quotation marks (e.g. -csvDecimalMark=","). + +**-sarifseverity** + + : This parameter sets the severity levels to be saved in the SARIF output. (1 - Info, 2 - Minor, 3 - Major, 4 - Critical, 5 - Blocker, c/C - CloneClass). The value should not be placed in quotation marks (e.g. -sarifseverity=2345c). The default value is 2345c. + +**-maximumThreads** + + : This parameter sets the maximum number of parallel tasks the controller can start. The default value is the number of available CPU cores on the current system. + +**-currentDate** + + : The name of the directory with date inside the result directory of the project. If it is not set, then the current date is used. + +**-cleanResults** + + : Cleans all but the last n number of timestamped result directories of the current project. + +**-cleanProject** + + : Removes all files created during the analysis from the given directory recursively. + +**-faultTolerant** + + : This parameter turns on or off the fault tolerant mode. In fault tolerant mode if any non critical error happens, then the analysis will continue and some of the results will be generated. Its value can be "true" (turn this feature on) or "false" (turn this feature off). The default value is "true". + +**-prefix** + + : We can give a certain prefix for the wrapped program names in Linux to wrapp special versions of these. If it is not set then the following commands are wrapped during the analysis: + : Linux: 'clang', 'clang++', 'ld', 'ar', 'ln' + : Windows: 'cl', 'lib', 'link', 'clang-cl', 'lld-link', 'llvm-lib' + +**-postfix** + + : We can give a certain postfix for the wrapped program names in Linux to wrapp special versions of these. If it is not set then the following commands are wrapped during the analysis: + : Linux: 'clang', 'clang++', 'ld', 'ar', 'ln' + : Windows: 'cl', 'lib', 'link', 'clang-cl', 'lld-link', 'llvm-lib + +**-runCppcheck** + : This parameter turns on or off the Cppcheck coding rule violation checking. With this feature, OpenStaticAnalyzer lists coding rule violations detected by Cppcheck. Its value can be "true" (turn this feature on) or "false" (turn this feature off). The default value is "true". + +**-runSQ** + + : Import issues from SonarQube server. + +**-SQHost** + + : The URL address of the SonarQube server. + +**-SQPort** + + : The port of the SonarQube server. + +**-SQProjectKey** + + : The key of the project in the SonarQube server. + +**-SQProjectPrefix** + + : Prefix path of the project's base directory (the path of the sonar-project.properties file). + +**-SQUserName** + + : The user name for the SonarQube server. + +**-SQPassword** + + : The password for the SonarQube server. + +**-SQLanguageKey** + + : The key of the language in SonarQube. + +**-runLIM2Patterns** + + : This parameter can be used to enable or disable the LIM2Patterns module during analysis (default = on). + +**-pattern** + + : The pattern file or pattern directory for LIM2Patterns. By default it searches for the predefined Anti Patterns found in Tools/Patterns/AntiPatterns. + +# Usage + +The following steps have to be performed to analyze the source code of a software system: + +1. The static analysis requires a build script, which contains the commands needed to compile the software system. If this build script is not readily available, it must be prepared as shown in the following example. + + ---------- build.bat ------------ + msbuild /t:Rebuild /p:Configuration=Release /p:Platform=Win32 Example.sln + + -------- build.sh ------------ + #!/bin/sh + export OSA_DISABLE_ANALYSIS=true + ./configure + unset OSA_DISABLE_ANALYSIS + ./make + + +2. Create hard and/or soft filter file(s) to filter out unnecessary (e.g. external, generated, or unit tests) source code, if necessary. + + ---------- SoftFilter.txt ------------ + -C:\\Users\\UserName\\MyProject\\src\\generated + +C:\\Users\\UserName\\MyProject + + ---------- HardFilter.txt -------- + -conftest + + +3. Execute OpenStaticAnalyzer: + + Example (Windows): + + C:\Users\UserName\OpenStaticAnalyzer\CPP\OpenStaticAnalyzerCPP + -projectName=MyProject + -buildScript=MyProject\\build.bat + -resultsDir=Results + -externalSoftFilter=SoftFilter.txt + -externalHardFilter=HardFilter.txt + + Example (Linux): + + ~$ OpenStaticAnalyzer/CPP/OpenStaticAnalyzerCPP + -projectName=MyProject + -buildScript=MyProject/build.sh + -resultsDir=Results + -externalSoftFilter=SoftFilter.txt + -externalHardFilter=HardFilter.txt + + +# Result files + +If any critical problems occur in the execution of the tools of the OpenStaticAnalyzer package during the code analysis, OpenStaticAnalyzer returns with non zero exit code. The error code of the given tool appears on the screen (detailed information on the bug can be found in the log directory), and the analysis stops, but the result files created until the failure are not deleted. Unless the fault tolerant mode is disabled the OpenStaticAnalyzer tries to generate as much result as it can with tolerating the not critical errors. If the fault tolerant mode is disabled with the faultTolerant parameter, then the analysis will stop in case of any error. + +An error-free execution of OpenStaticAnalyzer produces the following files: + +- Files containing the results of the static analysis in the results directory (set by the resultsDir parameter): + + - \$(projectName)\\cpp\\\$(DATE)\\\$(projectName)-\*.csv + + CSV (comma separated values) files containing different metrics: +Component, File, Namespace, Class, Interface, Enum, Method, Attribute, and Function level source code metrics, rule violation counts, and clone-related metrics at CloneClass and CloneInstance level. + + - \$(projectName)\\cpp\\\$(DATE)\\\$(projectName)-clones.txt + + List of the code clones (copy-pasted source code fragments) in the system. + + - \$(projectName)\\cpp\\\$(DATE)\\\$(projectName)-MetricHunter.txt + + List of the MetricHunter metric value violations in the system. + + - \$(projectName)\\cpp\\\$(DATE)\\\$(projectName)-ClangTidy.txt + + List of the clang-tidy coding rule violations in the system. + + - \$(projectName)\\cpp\\\$(DATE)\\\$(projectName)-Cppcheck.txt + + List of the Cppcheck coding rule violations in the system. + + - \$(projectName)\\cpp\\\$(DATE)\\\$(projectName).graph + + Binary representation of the result graph containing all the metrics, code clones and coding rule violations. + + - \$(projectName)\\cpp\\\$(DATE)\\\$(projectName).xml + + XML representation of the result graph containing all the metrics, code clones and coding rule violations. + + - \$(projectName)\\cpp\\\$(projectName).gsi + + Binary data file containing information for tracking the code clones through the consecutive revisions of the analyzed software system. + + - \$(projectName)\\cpp\\\$(DATE)\\\$(projectName).sarif + + SARIF representation of the rule violations. + + - \$(projectName)\\cpp\\\$(DATE)\\\$(projectName)-summary.graph + + Binary representation of the summary result graph containing only the System component node. + + - \$(projectName)\\cpp\\\$(DATE)\\\$(projectName)-summary.xml + + XML representation of the summary result graph containing only the System component node. + + - \$(projectName)\\cpp\\\$(DATE)\\\$(projectName)-summary.json + + JSON representation of the summary result graph containing only the System component node. + +- Other files and directories created in the results directory: + + - \$(projectName)\\cpp\\\$(DATE)\\openstaticanalyzer + + Directory, which contains configuration, binary, ASG, log, and temporary files created during the source code analysis. + + - \$(projectName)\\cpp\\\$(DATE)\\openstaticanalyzer\\asg + + Directory, which contains backup copies of the linked ASG and LIM files, the corresponding filter files, and the GSI file. + + - \$(projectName)\\cpp\\\$(DATE)\\openstaticanalyzer\\graph + + Directory, which contains backup copies of the graph files. + + - \$(projectName)\\cpp\\\$(DATE)\\openstaticanalyzer\\log + + Directory, which contains the log files created during the code analysis. + + - \$(projectName)\\cpp\\\$(DATE)\\openstaticanalyzer\\temp + + Directory, which contains the temporary files created during the code analysis. + +- Files created outside the results directory: + + - .csi + + C/C++ language dependent ASG file. The .csi files are created in the .columbus_cpp directory located in the directory of the corresponding object files of the compiled C/C++ source files. + + - .lcsi + + Linked C/C++ language dependent ASG file. It is created in the .columbus_cpp sub-directory of the directory containing the corresponding binary file (binary executable, shared object) produced by the linker programs. + + - .acsi + + Archive of C/C++ language dependent ASG files. The .acsi files are created in the .columbus_cpp directory located in the directory of the corresponding static library files produced by the ‘ar’ program. + + - .fcsi + + Filter file belonging to the linked C/C++ language dependent ASG file (.lcsi). It is created in the corresponding directory of the .lcsi file. + +# Coding rule violation suppression + +The warnings issued by the rule checker modules can be suppressed in case they are found to be invalid or for any other reason. In the case of the integrated 3^rd^ party Cppcheck tool and clang-tidy the warnings can be suppressed with the inline comment suppression mechanism of the tools. + +Example: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.cpp} +class A { + bool operator=(const A&) { + // cppcheck-suppress unusedVariable + int i; // NOLINT + } +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In this example, the "variable 'i' is not initialized" warning of the clang-tidy module and the "Unused variable" warning of Cppcheck will be suppressed. + +The warnings of MetricHunter cannot be suppressed at the moment. + +# Demo + +The Demo directory of the installation package contains the directory structure, the build and analyzer scripts for the analysis of an example project. +The log4cplus open source program is included as the example project, which can also be downloaded from the following URL: + +[http://sourceforge.net/projects/log4cplus/files/log4cplus-stable/1.1.0/log4cplus-1.1.0.tar.gz] + +[http://sourceforge.net/projects/log4cplus/files/log4cplus-stable/1.1.0/log4cplus-1.1.0.tar.gz]:http://sourceforge.net/projects/log4cplus/files/log4cplus-stable/1.1.0/log4cplus-1.1.0.tar.gz + +To perform the source code analysis of the demo project, the analyze.bat/analyze.sh script has to be executed. + +Contents of the Demo directory: + +Windows: + +----------- ---------------------------- -------------------------------------- +Demo\\ + log4cplus \# log4cplus project + log4cplus\\log4cplus-1.1.0 \# source code of log4cplus + log4cplus\\build.bat \# builds log4cplus + log4cplus\\analyze.bat \# starts the analysis + log4cplus\\softfilter.txt \# softfilter +----------- ---------------------------- -------------------------------------- + +Linux: + +----------- ---------------------------- -------------------------------------- +Demo/ + log4cplus \# log4cplus project + log4cplus/log4cplus-1.1.0 \# source code of log4cplus + log4cplus/build.sh \# builds log4cplus + log4cplus/analyze.sh \# starts the analysis + log4cplus/softfilter.txt \# softfilter +----------- ---------------------------- -------------------------------------- + +# Error messages + +- Message: Please set the resultsDir parameter. Under this directory a new directory with the name of the analyzed project will be created, if it does not exist yet. All results will be stored there under separate directories with their names containing the date and time. + + Solution: The resultsDir parameter must be set. + +- Message: Please set the projectName parameter to the name of the analyzed software system. + + Solution: The projectName parameter must be set. + +- Message: Please set the buildScript parameter. This is the script, which will build the project. + + Solution: The buildScript parameter must be set. + +# Known bugs and deficiencies + +Known bugs and deficiencies of OpenStaticAnalyzer for C/C++. + +- OpenStaticAnalyzer places the results into the directory specified by the projectName parameter. If special characters (like '\<', '\>', etc.) are used in the parameter, the analysis will probably fail. + +# FAQ + +Frequently Asked Questions regarding OpenStaticAnalyzer. + +- Problem: After starting the analysis, the computer does not show elevated load and none of the OpenStaticAnalyzer tools are running. + + Solution: OpenStaticAnalyzer creates temporary files during the analysis (e.g. tmp-wrapper.bat) which might be judged as suspicious by certain antivirus programs so they may block them. In these cases, the temporary files must be manually whitelisted. + +- Problem: On Windows platforms, in case of deep directory hierarchies, it may happen that the full paths of some files exceed 259 characters. In this case some OpenStaticAnalyzer tools may have problems with opening these files; they will terminate and write appropriate messages in the logs. + + Solution: Move the files to be analyzed to a directory closer to the file system root, or use the 'subst' shell command. + +- Problem: Analysis of a VS2008 project stops with a critical error of the CAN2Lim task. + + Solution: Use to 'devenv' command for building the project instead of the 'msbuild' or 'vcbuild' commands. + +# Appendices diff --git a/OpenStaticAnalyzer/cpp/doc/usersguide/md/SourceCodeMetricsRef.md b/OpenStaticAnalyzer/cpp/doc/usersguide/md/SourceCodeMetricsRef.md new file mode 100644 index 0000000..75dcc00 --- /dev/null +++ b/OpenStaticAnalyzer/cpp/doc/usersguide/md/SourceCodeMetricsRef.md @@ -0,0 +1,533 @@ +## Reference of source code metrics + +Source code metrics are used to quantify different source code characteristics. OpenStaticAnalyzer computes source code metrics for the following source code element kinds: components (e.g. executables), source files, namespaces, class types (including classes, structures, unions, interfaces, and enums), methods, and functions. Interfaces are defined as classes or structures that have only pure virtual functions and no data members. + +The calculated metrics are grouped into 6 categories, which are the following: + +- **Cohesion metrics:** measure to what extent the source code elements are coherent in the system. + +- **Complexity metrics:** measure the complexity of source code elements (typically algorithms). + +- **Coupling metrics:** measure the amount of interdependencies of source code elements. + +- **Documentation metrics:** measure the amount of comments and documentation of source code elements in the system. + +- **Inheritance metrics:** measure the different aspects of the inheritance hierarchy of the system. + +- **Size metrics:** measure the basic properties of the analyzed system in terms of different cardinalities (e.g. number of code lines, number of classes or methods). + +In the case of the documentation metrics all the comments found immediately before a source code element are considered as its documentation, while the comments contained inside the source code element are considered as its comments. + +The following table summarizes the metrics, their abbreviations and their correspondence to different source code element kinds. + + Category Metric name Abbreviation Class Component Enum File Function Interface Method Namespace Structure Union + ---------------------- -------------------------------------------- ------------- ------- ----------- ------ ------ ---------- ----------- -------- ----------- ----------- ------- + Cohesion metrics Lack of Cohesion in Methods 5 LCOM5 X X X + Complexity metrics McCabe's Cyclomatic Complexity McCC X X X + Weighted Methods per Class WMC X X X + Coupling metrics Coupling Between Object classes CBO X X X X + Number of Outgoing Invocations NOI X X X X X + Response set For Class RFC X X X + Documentation metrics API Documentation AD X X X X X X + Comment Lines of Code CLOC X X X X X X X X + Documentation Lines of Code DLOC X X X X X X X + Public Documented API PDA X X X X X X + Public Undocumented API PUA X X X X X X + Total API Documentation TAD X X + Total Comment Lines of Code TCLOC X X X X X X X X + Total Public Documented API TPDA X X + Total Public Undocumented API TPUA X X + Inheritance metrics Depth of Inheritance Tree DIT X X X + Number of Ancestors NOA X X X + Number of Children NOC X X X + Number of Descendants NOD X X X + Number of Parents NOP X X X + Size metrics Lines of Code LOC X X X X X X X X X + Logical Lines of Code LLOC X X X X X X X X X + Number of Classes NCL X + Number of Enums NEN X + Number of Getters NG X X X X X + Number of Interfaces NIN X + Number of Local Getters NLG X X X + Number of Local Methods NLM X X X + Number of Local Public Methods NLPM X X X + Number of Local Setters NLS X X X + Number of Methods NM X X X X X + Number of Packages NPKG X + Number of Parameters NUMPAR X X + Number of Public Methods NPM X X X X X + Number of Setters NS X X X X X + Number of Statements NOS X X X X X X + Number of Structures NST X + Number of Unions NUN X + Total Lines of Code TLOC X X X X X X X X X + Total Logical Lines of Code TLLOC X X X X X X X X X + Total Number of Classes TNCL X X + Total Number of Directories TNDI X X + Total Number of Enums TNEN X X + Total Number of Files TNFI X X + Total Number of Getters TNG X X X X X X + Total Number of Interfaces TNIN X X + Total Number of Local Getters TNLG X X X + Total Number of Local Methods TNLM X X X + Total Number of Local Public Methods TNLPM X X X + Total Number of Local Setters TNLS X X X + Total Number of Methods TNM X X X X X X + Total Number of Packages TNPKG X X + Total Number of Public Classes TNPCL X X + Total Number of Public Enums TNPEN X X + Total Number of Public Interfaces TNPIN X X + Total Number of Public Methods TNPM X X X X X X + Total Number of Public Structures TNPST X X + Total Number of Public Unions TNPUN X X + Total Number of Setters TNS X X X X X X + Total Number of Statements TNOS X X X X X X X + Total Number of Structures TNST X X + Total Number of Unions TNUN X X + +### Cohesion metrics + +#### Lack of Cohesion in Methods 5 (LCOM5) {#LCOM5} + +**Class, Structure, Union:** number of functionalities of the class. One of the basic principles of object-oriented programming is encapsulation, meaning that attributes belonging together and the operations that use them should be organized into one class, and one class shall implement only one functionality, i.e. its attributes and methods should be coherent. This metric measures the lack of cohesion and computes into how many coherent classes the class could be split. It is calculated by taking a non-directed graph, where the nodes are the implemented local methods of the class and there is an edge between the two nodes if and only if a common (local or inherited) attribute or abstract method is used or a method invokes another. The value of the metric is the number of connected components in the graph not counting those, which contain only constructors, destructors, getters, or setters. + + +### Complexity metrics + +#### McCabe's Cyclomatic Complexity (McCC) {#McCC} + +**Method, Function:** complexity of the method expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, for, foreach, range-based for, while, do-while, case label (which belongs to a switch instruction), catch, conditional expression (?:). Moreover, logical "and" (&&) and logical "or" (||) expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, switch, default label (which belongs to a switch instruction), try. + +**File:** complexity of the file expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, for, foreach, range-based for, while, do-while, case label (which belongs to a switch instruction), catch, conditional expression (?:). Moreover, logical "and" (&&) and logical "or" (||) expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, switch, default label (which belongs to a switch instruction), try. + + +#### Weighted Methods per Class (WMC) {#WMC} + +**Class, Structure, Interface:** complexity of the class expressed as the number of independent control flow paths in it. It is calculated as the sum of the McCabe's Cyclomatic Complexity (McCC) values of its local methods. + + +### Coupling metrics + +#### Coupling Between Object classes (CBO) {#CBO} + +**Class, Structure, Union, Interface:** number of directly used other classes (e.g. by inheritance, function call, type reference, attribute reference). Classes using many other classes highly depend on their environment, so it is difficult to test or reuse them; furthermore, they are very sensitive to the changes in the system. + + +#### Number of Outgoing Invocations (NOI) {#NOI} + +**Method, Function:** number of directly called methods. If a method is invoked several times, it is counted only once. + +**Class, Structure, Union:** number of directly called methods of other classes, including method invocations from attribute initializations. If a method is invoked several times, it is counted only once. + + +#### Response set For Class (RFC) {#RFC} + +**Class, Structure, Union:** number of local (i.e. not inherited) methods in the class (NLM) plus the number of directly invoked other methods by its methods or attribute initializations (NOI). + + +### Documentation metrics + +#### API Documentation (AD) {#AD} + +**Class, Structure, Union, Interface:** ratio of the number of documented public methods in the class +1 if the class itself is documented to the number of all public methods in the class + 1 (the class itself); however, the nested, anonymous, and local classes are not included. + +**Enum:** ratio of the number of documented enumerators in the enum +1 if the enum itself is documented to the number of all enumerators in the enum + 1 (the enum itself). + +**Namespace:** ratio of the number of documented public classes and methods in the namespace to the number of all of its public classes and methods; however, the classes and methods of its subnamespaces are not included. + + +#### Comment Lines of Code (CLOC) {#CLOC} + +**Method, Function:** number of comment and documentation code lines of the method; however, its anonymous and local classes are not included. + +**Class, Structure, Union, Interface:** number of comment and documentation code lines of the class, including its local methods and attributes; however, its nested, anonymous, and local classes are not included. + +**Namespace:** number of comment and documentation code lines of the namespace; however, its subnamespaces are not included. + +**File:** number of comment and documentation code lines of the file. + + +#### Documentation Lines of Code (DLOC) {#DLOC} + +**Method, Function:** number of documentation code lines of the method. + +**Class, Structure, Union, Interface:** number of documentation code lines of the class, including its local methods and attributes; however, its nested, anonymous, and local classes are not included. + +**Enum:** number of documentation code lines of the enum, including its enumerators. + + +#### Public Documented API (PDA) {#PDA} + +**Class, Structure, Union, Interface:** number of documented public methods in the class (+1 if the class itself is documented); however, the methods of its nested, anonymous, and local classes are not counted. + +**Namespace:** number of documented public classes and methods in the namespace; however, the classes and methods of its subnamespaces are not counted. + +**File:** number of documented public classes and methods in the file. + + +#### Public Undocumented API (PUA) {#PUA} + +**Class, Structure, Union, Interface:** number of undocumented public methods in the class (+1 if the class itself is undocumented); however, the methods of its nested, anonymous, and local classes are not counted. + +**Namespace:** number of undocumented public classes and methods in the namespace; however, the classes and methods of its subnamespaces are not counted. + +**File:** number of undocumented public classes and methods in the file. + + +#### Total API Documentation (TAD) {#TAD} + +**Namespace:** ratio of the number of documented public classes and methods in the namespace to the number of all of its public classes and methods, including its subnamespaces. + +**Component:** ratio of the number of documented public classes and methods in the component to the number of all of its public classes and methods, including its subcomponents. + + +#### Total Comment Lines of Code (TCLOC) {#TCLOC} + +**Method, Function:** number of comment and documentation code lines of the method, including its anonymous and local classes. + +**Class, Structure, Union, Interface:** number of comment and documentation code lines of the class, including its local methods and attributes, as well as its nested, anonymous, and local classes. + +**Namespace:** number of comment and documentation code lines of the namespace, including its subnamespaces. + +**Component:** number of comment and documentation code lines of the component, including its subcomponents. + + +#### Total Public Documented API (TPDA) {#TPDA} + +**Namespace:** number of documented public classes and methods in the namespace, including the documented public classes and methods of its subnamespaces. + +**Component:** number of documented public classes and methods in the component, including the documented public classes and methods of its subcomponents. + + +#### Total Public Undocumented API (TPUA) {#TPUA} + +**Namespace:** number of undocumented public classes and methods in the namespace, including the undocumented public classes and methods of its subnamespaces. + +**Component:** number of undocumented public classes and methods in the component, including the undocumented public classes and methods of its subcomponents. + + +### Inheritance metrics + +#### Depth of Inheritance Tree (DIT) {#DIT} + +**Class, Structure, Interface:** length of the path that leads from the class to its farthest ancestor in the inheritance tree. + + +#### Number of Ancestors (NOA) {#NOA} + +**Class, Structure, Interface:** number of classes, interfaces, enums and annotations from which the class is directly or indirectly inherited. + + +#### Number of Children (NOC) {#NOC} + +**Class, Structure, Interface:** number of classes, interfaces, enums and annotations which are directly derived from the class. + + +#### Number of Descendants (NOD) {#NOD} + +**Class, Structure, Interface:** number of classes, interfaces, enums, annotations, which are directly or indirectly derived from the class. + + +#### Number of Parents (NOP) {#NOP} + +**Class, Structure, Interface:** number of classes, interfaces, enums and annotations from which the class is directly inherited. + + +### Size metrics + +#### Lines of Code (LOC) {#LOC} + +**Method, Function:** number of code lines of the method, including empty and comment lines; however, its anonymous and local classes are not included. + +**Class, Structure, Union, Interface:** number of code lines of the class, including empty and comment lines, as well as its local methods; however, its nested, anonymous, and local classes are not included. + +**Enum:** number of code lines of the enum, including empty and comment lines. + +**Namespace:** number of code lines of the namespace, including empty and comment lines; however, its subnamespaces are not included. + +**File:** number of code lines of the file, including empty and comment lines. + + +#### Logical Lines of Code (LLOC) {#LLOC} + +**Method, Function:** number of non-empty and non-comment code lines of the method; however, its anonymous and local classes are not included. + +**Class, Structure, Union, Interface:** number of non-empty and non-comment code lines of the class, including the non-empty and non-comment lines of its local methods; however, its nested, anonymous, and local classes are not included. + +**Enum:** number of non-empty and non-comment code lines of the enum. + +**Namespace:** number of non-empty and non-comment code lines of the namespace; however, its subnamespaces are not included. + +**File:** number of non-empty and non-comment code lines of the file. + + +#### Number of Classes (NCL) {#NCL} + +**Namespace:** number of classes in the namespace; however, the classes of its subnamespaces are not included. + + +#### Number of Enums (NEN) {#NEN} + +**Namespace:** number of enums in the namespace; however, the enums of its subnamespaces are not included. + + +#### Number of Getters (NG) {#NG} + +**Class, Structure, Union, Interface:** number of getter methods in the class, including the inherited ones; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted. + +**Namespace:** number of getter methods in the namespace; however, getter methods of its subnamespaces are not included. + + +#### Number of Interfaces (NIN) {#NIN} + +**Namespace:** number of interfaces in the namespace; however, the interfaces of its subnamespaces are not included. + + +#### Number of Local Getters (NLG) {#NLG} + +**Class, Structure, Interface:** number of local (i.e. not inherited) getter methods in the class; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted. + + +#### Number of Local Methods (NLM) {#NLM} + +**Class, Structure, Interface:** number of local (i.e. not inherited) methods in the class; however, the methods of nested, anonymous, and local classes are not included. + + +#### Number of Local Public Methods (NLPM) {#NLPM} + +**Class, Structure, Interface:** number of local (i.e. not inherited) public methods in the class; however, the methods of nested, anonymous, and local classes are not included. + + +#### Number of Local Setters (NLS) {#NLS} + +**Class, Structure, Interface:** number of local (i.e. not inherited) setter methods in the class; however, the setter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted. + + +#### Number of Methods (NM) {#NM} + +**Class, Structure, Union, Interface:** number of methods in the class, including the inherited ones; however, the methods of its nested, anonymous and local classes are not included. Methods that override abstract methods are not counted. + +**Namespace:** number of methods in the namespace; however, methods of its subnamespaces are not included. + + +#### Number of Packages (NPKG) {#NPKG} + +**Namespace:** number of directly contained subnamespaces of the namespace. + + +#### Number of Parameters (NUMPAR) {#NUMPAR} + +**Method, Function:** number of the parameters of the method. The varargs parameter counts as one. + + +#### Number of Public Methods (NPM) {#NPM} + +**Class, Structure, Union, Interface:** number of public methods in the class, including the inherited ones; however, the public methods of nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted. + +**Namespace:** number of public methods in the namespace; however, the public methods of its subnamespaces are not included. + + +#### Number of Setters (NS) {#NS} + +**Class, Structure, Union, Interface:** number of setter methods in the class, including the inherited ones; however, the setter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted. + +**Namespace:** number of setter methods in the namespace; however, setter methods of its subnamespaces are not included. + + +#### Number of Statements (NOS) {#NOS} + +**Method, Function:** number of statements in the method; however, the statements of its anonymous and local classes are not included. + +**Class, Structure, Union:** number of statements in the class; however, the statements of its nested, anonymous, and local classes are not included. + +**File:** number of statements in the file. + + +#### Number of Structures (NST) {#NST} + +**Namespace:** number of structures in the namespace; however, the structures of its subnamespaces are not included. + + +#### Number of Unions (NUN) {#NUN} + +**Namespace:** number of unions in the namespace; however, the unions of its subnamespaces are not included. + + +#### Total Lines of Code (TLOC) {#TLOC} + +**Method, Function:** number of code lines of the method, including empty and comment lines, as well as its anonymous and local classes. + +**Class, Structure, Union, Interface:** number of code lines of the class, including empty and comment lines, as well as its local methods, anonymous, local, and nested classes. + +**Namespace:** number of code lines of the namespace, including empty and comment lines, as well as its subnamespaces. + +**Component:** number of code lines of the component, including empty and comment lines, as well as its subcomponents. + + +#### Total Logical Lines of Code (TLLOC) {#TLLOC} + +**Method, Function:** number of non-empty and non-comment code lines of the method, including the non-empty and non-comment lines of its anonymous and local classes. + +**Class, Structure, Union, Interface:** number of non-empty and non-comment code lines of the class, including the non-empty and non-comment code lines of its local methods, anonymous, local, and nested classes. + +**Namespace:** number of non-empty and non-comment code lines of the namespace, including its subnamespaces. + +**Component:** number of non-empty and non-comment code lines of the component, including its subcomponents. + + +#### Total Number of Classes (TNCL) {#TNCL} + +**Namespace:** number of classes in the namespace, including the classes of its subnamespaces. + +**Component:** number of classes in the component, including the classes of its subcomponents. + + +#### Total Number of Directories (TNDI) {#TNDI} + +**Namespace:** number of directories that belong to the namespace, including the directories of its subnamespaces. + +**Component:** number of directories that belong to the component, including its subcomponents. + + +#### Total Number of Enums (TNEN) {#TNEN} + +**Namespace:** number of enums in the namespace, including the enums of its subnamespaces. + +**Component:** number of enums in the component, including the enums of its subcomponents. + + +#### Total Number of Files (TNFI) {#TNFI} + +**Namespace:** number of files that belong to the namespace, including the files of its subnamespaces. + +**Component:** number of files that belong to the component, including its subcomponents. + + +#### Total Number of Getters (TNG) {#TNG} + +**Class, Structure, Union, Interface:** number of getter methods in the class, including the inherited ones, as well as the inherited and local getter methods of its nested, anonymous and local classes. + +**Namespace:** number of getter methods in the namespace, including the getter methods of its subnamespaces. + +**Component:** number of getter methods in the component, including the getter methods of its subcomponents. + + +#### Total Number of Interfaces (TNIN) {#TNIN} + +**Namespace:** number of interfaces in the namespace, including the interfaces of its subnamespaces. + +**Component:** number of interfaces in the component, including the interfaces of its subcomponents. + + +#### Total Number of Local Getters (TNLG) {#TNLG} + +**Class, Structure, Interface:** number of local (i.e. not inherited) getter methods in the class, including the local getter methods of its nested, anonymous, and local classes. + + +#### Total Number of Local Methods (TNLM) {#TNLM} + +**Class, Structure, Interface:** number of local (i.e. not inherited) methods in the class, including the local methods of its nested, anonymous, and local classes. + + +#### Total Number of Local Public Methods (TNLPM) {#TNLPM} + +**Class, Structure, Interface:** number of local (i.e. not inherited) public methods in the class, including the local methods of its nested, anonymous, and local classes. + + +#### Total Number of Local Setters (TNLS) {#TNLS} + +**Class, Structure, Interface:** number of local (i.e. not inherited) setter methods in the class, including the local setter methods of its nested, anonymous, and local classes. + + +#### Total Number of Methods (TNM) {#TNM} + +**Class, Structure, Union, Interface:** number of methods in the class, including the inherited ones, as well as the inherited and local methods of its nested, anonymous, and local classes. Methods that override abstract methods are not counted. + +**Namespace:** number of methods in the namespace, including the methods of its subnamespaces. + +**Component:** number of methods in the component, including the methods of its subcomponents. + + +#### Total Number of Packages (TNPKG) {#TNPKG} + +**Namespace:** number of subnamespaces in the namespace, including all directly or indirectly contained subnamespaces. + +**Component:** number of namespaces and subnamespaces that belong to the component, including its subcomponents. + + +#### Total Number of Public Classes (TNPCL) {#TNPCL} + +**Namespace:** number of public classes in the namespace, including the public classes of its subnamespaces. + +**Component:** number of public classes in the component, including the public classes of its subcomponents. + + +#### Total Number of Public Enums (TNPEN) {#TNPEN} + +**Namespace:** number of public enums in the namespace, including the public enums of its subnamespaces. + +**Component:** number of public enums in the component, including the public enums of its subcomponents. + + +#### Total Number of Public Interfaces (TNPIN) {#TNPIN} + +**Namespace:** number of public interfaces in the namespace, including the public interfaces of its subnamespaces. + +**Component:** number of public interfaces in the component, including the public interfaces of its subcomponents. + + +#### Total Number of Public Methods (TNPM) {#TNPM} + +**Class, Structure, Union, Interface:** number of public methods in the class, including the inherited ones, as well as the inherited and local public methods of its nested, anonymous, and local classes. + +**Namespace:** number of public methods in the namespace, including the public methods of its subnamespaces. + +**Component:** number of public methods in the component, including the public methods of its subcomponents. + + +#### Total Number of Public Structures (TNPST) {#TNPST} + +**Namespace:** number of public structures in the namespace, including the public structures of its subnamespaces. + +**Component:** number of public structures in the component, including the public structures of its subcomponents. + + +#### Total Number of Public Unions (TNPUN) {#TNPUN} + +**Namespace:** number of public unions in the namespace, including the public unions of its subnamespaces. + +**Component:** number of public unions in the component, including the public unions of its subcomponents. + + +#### Total Number of Setters (TNS) {#TNS} + +**Class, Structure, Union, Interface:** number of setter methods in the class, including the inherited ones, as well as the inherited and local setter methods of its nested, anonymous and local classes. + +**Namespace:** number of setter methods in the namespace, including the setter methods of its subnamespaces. + +**Component:** number of setter methods in the component, including the setter methods of its subcomponents. + + +#### Total Number of Statements (TNOS) {#TNOS} + +**Method, Function:** number of statements in the method, including the statements of its anonymous and local classes. + +**Class, Structure, Union:** number of statements in the class, including the statements of its nested, anonymous, and local classes. + +**Namespace:** number of statements in the namespace, including the statements of its subnamespaces. + +**Component:** number of statements in the component, including the statements of its subcomponents. + + +#### Total Number of Structures (TNST) {#TNST} + +**Namespace:** number of structures in the namespace, including the structures of its subnamespaces. + +**Component:** number of structures in the component, including the structures of its subcomponents. + + +#### Total Number of Unions (TNUN) {#TNUN} + +**Namespace:** number of unions in the namespace, including the unions of its subnamespaces. + +**Component:** number of unions in the component, including the unions of its subcomponents. diff --git a/OpenStaticAnalyzer/cpp/doc/usersguide/md/WrappingTips.md b/OpenStaticAnalyzer/cpp/doc/usersguide/md/WrappingTips.md new file mode 100644 index 0000000..9891ea4 --- /dev/null +++ b/OpenStaticAnalyzer/cpp/doc/usersguide/md/WrappingTips.md @@ -0,0 +1,202 @@ +# Tips for compiler-wrapping + +In this chapter we describe our compiler-wrapping technique more in-depth and provide some tips for analyzing projects with non-trivial build systems. + +In a previous chapter called *Preconditions*, we have described what conditions are required to run the analysis of a project in a normal scenario. In this chapter we try to answer why those preconditions are necessary and show you what kind of modifications are required to make the compiler-wrapping technique work. In our experience, every build can be wrapped with modifying only a couple of lines of the build scripts, but to know what you have to change, you have to understand the basics of compiler wrapping. + +## Overview of our compiler-wrapping technique + +In order to analyze your project, a list of your .cpp and .h files is not enough for us to plot the connections between your code, your headers, your executables, your static or dynamic libraries, etc. We need to eavesdrop on your whole build process. We do this by redirecting the compile, link and library creating commands of your buildtool man-in-the-middle style. Let us illustrate that through an example: + +Let's say you have a Visual Studio 2017 project on Windows that you intend to compile with the regular MSVC tools. You can do this from the command line by setting up a native environment (running vcvarsall.bat) and calling msbuild on your project. Normally, this uses the cl.exe from Program Files to compile .cpp files, however, that's not good for us, because we would like to hijack cl.exe to log the compiled files and flags and macros used for the compilation. + +So instead of that, whenever you call msbuild from inside the build.bat script, we automatically call msbuild with the /p:UseEnv=True parameter added to it. The result of this, is that the cl.exe, link.exe and lib.exe commands used by the msbuild are now the ones found in PATH and NOT the ones from Program Files . All we do now is put our fake cl.exe, lib.exe and link.exe files on PATH. These fake executables will log their received parameters, and forward everything to the real .exe files (in Program Files). This is the gist of compiler-wrapping. + +Here is the rough scheme of the OpenStaticAnalyzer code analysis from the perspective of compiler-wrapping (Windows/Linux): + +1. Open cmd/shell + +2. Put compiler programs on PATH (on Windows: run the correct version of vcvarsall.bat; on Linux: add clang and clang++ to PATH (if not already there)) + +3. Run OpenStaticAnalyzerCPP.exe (with your build.bat/build.sh script supplied as a parameter) + +4. The program will create fake compiler tools(fake cl.exe/clang) that log their parameters and forward them to the real one. Also the program adds these fake compiler tools to the top of PATH (shadowing the real ones). + +5. The program calls build.bat/build.sh (that you have supplied), which builds your project with the fake compiler tools from PATH. + +6. In-depth analysis is run over your source files (which were gathered by the fake compiler tools) + +Note1: Your build.bat/build.sh **MUST invoke a full build** (as we need to gather all the files)! This usually means rebuild in build.bat/build.sh. +Note2: No matter what build system you use, you need to configure it somehow to call the compile, link and lib commands from PATH (instead of some other absolute or relative paths) +Note3: Your build script should not put any of these compiler tools on PATH (as it would shadow our fake compiler tools) + +If you cannot guarantee all these, the compiler-wrapping technique won't work. + +## Examples of non-trivial build.bat/build.sh scripts + +Writing the correct build.bat/build.sh scripts can be tricky, here are some examples to help: + +**1. cmake + ninja on Windows** +This is the build.bat for the project wasm3, using a CMake Ninja generator and building with Ninja: +``` +set OLDDIR=%CD% +cd %~dp0 + +rmdir /Q /S build +mkdir build +cd build +SET OSA_DISABLE_ANALYSIS=true +cmake -GNinja ..\wasm3 +SET OSA_DISABLE_ANALYSIS= +ninja +chdir /d %OLDDIR% +``` +Note1: Ninja doesn't have a rebuild switch, so we need to delete the build folder and recreate it. +Note2: Ninja uses the compiler paths hard coded into build.ninja by the CMake generator. CMake acquired these paths from the PATH (this is why we must put the CMake generator into the build.bat) +Note3: The compiler is the msvc cl.exe found on PATH (put there by vcvarsall.bat). Currently, on Windows our tools can only analyze projects compiled with cl.exe +Note4: The CMake Ninja generator compiles some tools for itself, therefore we must SET OSA_DISABLE_ANALYSIS=true surrounding the CMake generator call (we don't want to include CMake's own compiled tools into the analysis results) + +**2. cmake + make with clang on Linux** +This is the build.sh script for project wasm3, using the default make generator of CMake with clang on Linux. +``` +export OSA_DISABLE_ANALYSIS=true && +export CXX=clang++ && +export CC=clang && +rm -rf build && +mkdir build && +cd build && +/usr/bin/cmake ../wasm3 && +unset OSA_DISABLE_ANALYSIS && +make -j8 +``` +Note1: As it is written earlier, you must use clang to compile and analyze your project on Linux. GCC is not yet supported. +Note2: clang and clang++ are already on PATH by default but we have to export them as CXX and CC variables for CMake to find the right compilers. +Note3: We use && to separate the commands here, but you could also use ; + +**3. cmake + cmake --build on Windows ** +This is the build.bat script for project wasm3, using the CMake Visual Studio 2019 generator and the cmake --build command. +``` +set OLDDIR=%CD% +cd %~dp0 + +rmdir /Q /S build +mkdir build +cd build +SET OSA_DISABLE_ANALYSIS=true +cmake -G"Visual Studio 16 2019" -A x64 ..\wasm3 +SET OSA_DISABLE_ANALYSIS= +cmake --build . --config Release -- /p:UseEnv=True +chdir /d %OLDDIR% +``` +Note1: The --build command of CMake builds the project with the build tool decided by the generator being used. For VS projects, this is msbuild. Unfortunetly, we cannot supply the cmake VS generator with compilers from PATH (the path to the tools in the CMake VS generator are taken from the registry). What we can do, however, is provide the /p:UseEnv=True parameter to msbuild to force it to use the tools from the environment. In the CMake command, every parameter after -- is forwarded to the buildtool. +Note2: Just like ninja, cmake --build also does not have a rebuild flag. We have two options: pass the rebuild parameter to msbuild after the --, or delete and recreate the build folders. We chose the latter here. + +**4. custom configuration script + nmake on Windows** +This is the build.bat script for the project QTBase, it uses a custom configuration script and an nmake build on Windows. +``` +set OLDDIR=%CD% +cd %~dp0 + +rmdir /Q /S build +mkdir build +cd build +SET OSA_DISABLE_ANALYSIS=true +call ..\qt5vars.cmd +echo y | call ..\qtbase\configure -debug -no-pch -nomake examples^ + -nomake tests -skip qtwebengine -opensource -prefix "C:\projektek\tests\qtbase\build" +SET OSA_DISABLE_ANALYSIS= +call nmake +cd .. +chdir /d %OLDDIR% +``` +Note1: We had to use a caret(^) in the script to break the line so that the lines in this documentation are not too long. You don't have to do that in your script. +Note2: There was no need to change the custom configuration scripts of the project here. Just follow the regular protocol. The only tricky thing is to prefix the configuration with "echo y |". This will result in automatic "yes" user input for prompts (which happen during configuration). + +## Examples of build/configuration script modifications + +In rare cases, a clever build.bat/build.sh is not enough, we need to modify the configuration/build scripts. Here are some examples of things to avoid and what to do instead. + +**1. Do not depend on the path of compiler tools in the build/configuration scripts!** + +This is a snippet of the CMakeLists.txt of the msvc/STL project. You can see that the TOOLSET_LIB variable is set based on a path relative to the CMAKE_CXX_COMPILER variable (which is the path to cl.exe in this case). Since we replace the cl.exe on PATH with our own fake one, this relative path will not work, so don't do this: + +CMakeLists.txt (snippet): +``` +get_filename_component(TOOLSET_BINARIES_DIR "${CMAKE_CXX_COMPILER}" DIRECTORY) # $\VC\Tools\MSVC\14.23.27931\bin\Hostx86\x86 +get_filename_component(TOOLSET_ROOT_DIR "${TOOLSET_BINARIES_DIR}" DIRECTORY) # $\VC\Tools\MSVC\14.23.27931\bin\Hostx86 +get_filename_component(TOOLSET_ROOT_DIR "${TOOLSET_ROOT_DIR}" DIRECTORY) # $\VC\Tools\MSVC\14.23.27931\bin +get_filename_component(TOOLSET_ROOT_DIR "${TOOLSET_ROOT_DIR}" DIRECTORY) # $\VC\Tools\MSVC\14.23.27931 + +set(TOOLSET_LIB "${TOOLSET_ROOT_DIR}/lib/${VCLIBS_X86_OR_X64}") +``` + +Instead, you have two options. One is to set it as an absolute path: (not the best solution but it works) + +CMakeLists.txt (snippet): +``` +if (DEFINED ENV{OPENSTATICANALYZER_IS_ACTIVE}) + set(TOOLSET_ROOT_DIR "C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.24.28314") +endif() +set(TOOLSET_LIB "${TOOLSET_ROOT_DIR}/lib/${VCLIBS_X86_OR_X64}") +``` +Note1: You can always use the environmental variable OPENSTATICANALYZER_IS_ACTIVE to check whether the build is under the analysis of OpenStaticAnalyzer (this will guarantee that these modifications won't affect your regular build). + +A better solution is to create the relative path based on cl.exe BEFORE the OpenStaticAnalyzerCPP.exe is called (while you still have the original cl.exe on top of PATH). To do this, we have to make a short script that calls OpenStaticAnalyzerCPP.exe, instead of calling it directly: + +analyze.bat: +``` +:: Putting the right compiler tools in PATH +call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 +:: These 3 lines are just a cmd trick to copy the file-path of cl.exe (from PATH) into a variable +where cl > tmpFile +set /p cl_path_env_var= < tmpFile +del tmpFile +:: Setting up the proper VC root path relative to the cl.exe on PATH +:: We will be able to find this variable(ENV_ORIGINAL_TOOLSET_ROOT_DIR) in CMakeLists.txt and use it. +set ENV_ORIGINAL_TOOLSET_ROOT_DIR=%cl_path_env_var%\..\..\..\.. + +N:\buildR\OpenStaticAnalyzer\OpenStaticAnalyzer-5.0.0-x64-Windows\CPP\OpenStaticAnalyzerCPP.exe^ + -projectName=STL -buildScript=build.bat -resultsDir=Results\clang -externalSoftFilter=softfilter +``` +Note1: We had to use a caret(^) in the script to break the line so that the lines in this documentation are not too long. You don't have to do that in your script. + +Here is how you use that variable in the modified CMakeLists.txt: + +CMakeLists.txt (snippet): +``` +if (DEFINED ENV{ENV_ORIGINAL_TOOLSET_ROOT_DIR}) + file(TO_CMAKE_PATH "$ENV{ENV_ORIGINAL_TOOLSET_ROOT_DIR}" TOOLSET_ROOT_DIR) +endif() +``` + +**2. Do not put compiler tools on PATH while building!** + +This is a snippet of the custom build script of Panda3d, you can see that it adds the compiler binary path to the PATH variable, but your build script shouldn't do this: + +makepandacore.py (snippet): +``` +vc_binpath = SDK["VISUALSTUDIO"] + vcdir_suffix + "bin" +binpath = os.path.join(vc_binpath, bindir) +if not os.path.isfile(binpath + "\\cl.exe"): + # Try the x86 tools, those should work just as well. + if arch == 'x64' and os.path.isfile(vc_binpath + "\\x86_amd64\\cl.exe"): + binpath = "{0}\\x86_amd64;{0}".format(vc_binpath) + elif winsdk_ver.startswith('10.'): + exit("Couldn't find compilers in %s. You may need to install the Windows SDK 7.1." % binpath) + else: + exit("Couldn't find compilers in %s." % binpath) + +AddToPathEnv("PATH", binpath) # <-- This line causes the problem, don't do this! +``` + +Instead, given that we have to put the compiler tools on PATH anyways (with vcvarsall.bat), we can simply disable it by adding an IF check with our OPENSTATICANALYZER_IS_ACTIVE environmental variable: + +makepandacore.py (snippet): +``` +# If this enviromental variable is set, we know that the build is called from the OpenStaticAnalyzer analysis +# Therefore, we only do this if the build is NOT called from OpenStaticAnalyzer +if (os.environ.get('OPENSTATICANALYZER_IS_ACTIVE') == None): + AddToPathEnv("PATH", binpath) +``` + +Hopefully, with these hints you will be able to run the analysis on your project successfully. **If not, send us an email and we will help you sort it out!** diff --git a/OpenStaticAnalyzer/csharp/CMakeLists.txt b/OpenStaticAnalyzer/csharp/CMakeLists.txt index 457947f..01a8f77 100644 --- a/OpenStaticAnalyzer/csharp/CMakeLists.txt +++ b/OpenStaticAnalyzer/csharp/CMakeLists.txt @@ -42,9 +42,9 @@ add_custom_generated_copy_dependency_to_tools_dir (MetricHunter_csharp${EXE} Met add_custom_generated_copy_dependency_to_tools_dir (MetricHunter_CSHARP.threshold MetricHunter_csharp_copy_MetricHunter_CSHARP.threshold MetricHunter.threshold) add_custom_generated_copy_dependency_to_tools_dir (UserDefinedMetrics${EXE}) add_custom_generated_copy_dependency_to_tools_dir (Sonar2Graph${EXE}) -add_custom_generated_copy_dependency_to_tools_dir (LIM2Patterns_csharp${EXE} LIM2Patterns_csharp LIM2Patterns${EXE}) -add_custom_generated_copy_dependency_to_tools_dir (Patterns LIM2Patterns_csharp Patterns DIRECTORY) -add_custom_generated_copy_dependency_to_tools_dir (Lib LIM2Patterns_csharp Lib DIRECTORY) +add_custom_generated_copy_dependency_to_tools_dir (LIM2Patterns${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (Patterns LIM2Patterns Patterns DIRECTORY) +add_custom_generated_copy_dependency_to_tools_dir (Lib LIM2Patterns Lib DIRECTORY) add_custom_generated_copy_dependency_to_tools_dir (Roslyn2Graph${EXE}) foreach (BINARY ${CSAN_BINARIES}) diff --git a/OpenStaticAnalyzer/csharp/doc/usersguide/md/Main.md b/OpenStaticAnalyzer/csharp/doc/usersguide/md/Main.md index d697b4e..6407e5d 100644 --- a/OpenStaticAnalyzer/csharp/doc/usersguide/md/Main.md +++ b/OpenStaticAnalyzer/csharp/doc/usersguide/md/Main.md @@ -21,7 +21,7 @@ The most important product characteristics of OpenStaticAnalyzer are the followi - Coding issue detection: - Metric threshold violations (MetricHunter module) - + - FxCop coding rule violations - SONARQUBE™ platform 8.0 (“SonarQube” in the following) coding rule violations @@ -159,9 +159,9 @@ OpenStaticAnalyzer can be executed with the following parameters: **-projectName** : The name of the analyzed software system. The name specified here will be used for storing the results. - + **-input** - + : The solution (.sln), project (.csproj) or C# source (.cs) file to analyse. **-externalHardFilter** @@ -273,15 +273,15 @@ Source code elements in the files marked with darker background will not be cons **-runFxCop** : This parameter turns on or off the FxCop coding rule violation checking. With this feature, OpenStaticAnalyzer lists coding rule violations detected by FxCop. Its value can be "true" (turn this feature on) or "false" (turn this feature off). The default value is "true". FxCop is only able to run if there was a successful build of the given project with pdb files generated. - + **-FxCopPath** - + : Specifies the the directory which contains the FxCop binaries. If not provided, the program will search through the installed Visual Studio directories and use the latest one if found. **-configuration** : The name of the project configuration. - + **-platform** : The name of the target platform. @@ -325,7 +325,7 @@ Source code elements in the files marked with darker background will not be cons **-pattern** : The pattern file or pattern directory for LIM2Patterns. By default it searches for the predefined Anti Patterns found in Tools/Patterns/AntiPatterns. - + # Usage Execute the following command to analyse the source code of a software system: diff --git a/OpenStaticAnalyzer/csharp/doc/usersguide/md/SourceCodeMetricsRef.md b/OpenStaticAnalyzer/csharp/doc/usersguide/md/SourceCodeMetricsRef.md index 33d4ea4..16f875a 100644 --- a/OpenStaticAnalyzer/csharp/doc/usersguide/md/SourceCodeMetricsRef.md +++ b/OpenStaticAnalyzer/csharp/doc/usersguide/md/SourceCodeMetricsRef.md @@ -24,22 +24,16 @@ The following table summarizes the metrics, their abbreviations and their corres ---------------------- ---------------------------------------- ------------- ------- ----------- ---------- ------ ------ ----------- -------- ----------- ----------- Cohesion metrics Lack of Cohesion in Methods 5 LCOM5 X X Complexity metrics McCabe's Cyclomatic Complexity McCC X X - Nesting Level NL X X X - Nesting Level Else-If NLE X X X Weighted Methods per Class WMC X X Coupling metrics Coupling Between Object classes CBO X X X - Coupling Between Object classes Inverse CBOI X X X - Number of Incoming Invocations NII X X X X Number of Outgoing Invocations NOI X X X Response set For Class RFC X X Documentation metrics API Documentation AD X X X X X Comment Density CD X X X X X - Comment Lines of Code CLOC X X X X X X X Documentation Lines of Code DLOC X X X X X X Public Documented API PDA X X X X X Public Undocumented API PUA X X X X X Total API Documentation TAD X X - Total Comment Density TCD X X X X X X Total Comment Lines of Code TCLOC X X X X X X X Total Public Documented API TPDA X X Total Public Undocumented API TPUA X X @@ -50,43 +44,35 @@ The following table summarizes the metrics, their abbreviations and their corres Number of Parents NOP X X X Size metrics Lines of Code LOC X X X X X X X X Logical Lines of Code LLOC X X X X X X X X - Number of Attributes NA X X X X X Number of Classes NCL X Number of Enums NEN X Number of Getters NG X X X X Number of Interfaces NIN X - Number of Local Attributes NLA X X X Number of Local Getters NLG X X X Number of Local Methods NLM X X X - Number of Local Public Attributes NLPA X X X Number of Local Public Methods NLPM X X X Number of Local Setters NLS X X X Number of Methods NM X X X X Number of Packages NPKG X Number of Parameters NUMPAR X - Number of Public Attributes NPA X X X X Number of Public Methods NPM X X X X Number of Setters NS X X X X Number of Statements NOS X X X Number of Structures NST X Total Lines of Code TLOC X X X X X X X X Total Logical Lines of Code TLLOC X X X X X X X X - Total Number of Attributes TNA X X X X X Total Number of Classes TNCL X X Total Number of Directories TNDI X X Total Number of Enums TNEN X X Total Number of Files TNFI X X Total Number of Getters TNG X X X X X Total Number of Interfaces TNIN X X - Total Number of Local Attributes TNLA X X X X Total Number of Local Getters TNLG X X X X Total Number of Local Methods TNLM X X X X - Total Number of Local Public Attributes TNLPA X X X X Total Number of Local Public Methods TNLPM X X X X Total Number of Local Setters TNLS X X X X Total Number of Methods TNM X X X X X Total Number of Packages TNPKG X X - Total Number of Public Attributes TNPA X X X X X Total Number of Public Classes TNPCL X X Total Number of Public Enums TNPEN X X Total Number of Public Interfaces TNPIN X X @@ -108,18 +94,6 @@ The following table summarizes the metrics, their abbreviations and their corres **Method:** complexity of the method expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is initially 1 which increases by 1 for each occurence of the following instructions: if, for, foreach, while, do-while, case label (label that belongs to a switch instruction), catch (handler that belongs to a try block), conditional statement (?:) and conditional access operators (?. and ?[]). Moreover, logical and (&&), logical or (||) and null coalescing (??) expressions also add to the final value because their short-circuit evalutaion can cause branching depending on the first operand. The following language elements do not increase the value: else, try, switch, default label (default label that belongs to a switch instruction), finally. -#### Nesting Level (NL) {#NL} - -**Method:** complexity of the method expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes. The following instructions are taken into account: if, else-if, else, for, foreach, while, do-while, switch, try, catch, finally, lock, checked, unchecked, fixed, using statement, conditional statement (?:) and block statements that are directly inside another block statement. The following instructions do not increase the value by themselves; however, if additional embeddednesses can be found in their blocks, they are considered: case and default label. - -**Class, Structure:** complexity of the class expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes. It is calculated as the maximum nesting level (NL) of its local methods. - -#### Nesting Level Else-If (NLE) {#NLE} - -**Method:** complexity of the method expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes, where in the if-else-if construct only the first if instruction is considered. The following instructions are taken into account: if, for, foreach, while, do-while, switch, try, catch, finally, lock, checked, unchecked, fixed, using statement, conditional statement (?:) and block statements that are directly inside another block statement. The following instructions do not increase the value by themselves; however, if additional embeddednesses can be found in their blocks, they are considered: else, else-if (i.e. in the if-else-if construct the use of else-if does not increase the value of the metric), case and default label. - -**Class, Structure:** complexity of the class expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes, where in the if-else-if construct only the first if instruction is considered. It is calculated as the maximum nesting level (NLE) of its local methods. - #### Weighted Methods per Class (WMC) {#WMC} **Class, Structure:** complexity of the class expressed as the number of independent control flow paths in it. It is calculated as the sum of the McCabe's Cyclomatic Complexity (McCC) values of its local methods. @@ -130,16 +104,6 @@ The following table summarizes the metrics, their abbreviations and their corres **Class, Structure:** number of directly used other classes (e.g. by inheritance, function call, type reference, attribute reference). Classes using many other classes highly depend on their environment, so it is difficult to test or reuse them; furthermore, they are very sensitive to the changes in the system. -#### Coupling Between Object classes Inverse (CBOI) {#CBOI} - -**Class, Structure:** number of other classes, which directly use the class. Classes which are used by many other classes have a high impact on the behavior of the system, and should be modified very carefully and tested intensively. - -#### Number of Incoming Invocations (NII) {#NII} - -**Method:** number of other methods and attribute initializations which directly call the method. If the method is invoked several times from the same method or attribute initialization, it is counted only once. - -**Class, Structure:** number of other methods and attribute initializations which directly call the local methods of the class. If a method is invoked several times from the same method or attribute initialization, it is counted only once. - #### Number of Outgoing Invocations (NOI) {#NOI} **Method:** number of directly called methods. If a method is invoked several times, it is counted only once. @@ -158,14 +122,6 @@ The following table summarizes the metrics, their abbreviations and their corres **Namespace:** ratio of the number of documented public classes and methods in the namespace to the number of all of its public classes and methods; however, the classes and methods of its subnamespaces are not included. -#### Comment Density (CD) {#CD} - -**Method:** ratio of the comment lines of the method (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC). - -**Class, Structure:** ratio of the comment lines of the class (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC). - -**Namespace:** ratio of the comment lines of the namespace (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC). - #### Comment Lines of Code (CLOC) {#CLOC} **Method:** number of comment and documentation code lines of the method; however, its anonymous classes are not included. @@ -198,16 +154,6 @@ The following table summarizes the metrics, their abbreviations and their corres **Component:** ratio of the number of documented public classes and methods in the component to the number of all of its public classes and methods, including its subcomponents. -#### Total Comment Density (TCD) {#TCD} - -**Method:** ratio of the total comment lines of the method (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). - -**Class, Structure:** ratio of the total comment lines of the class (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). - -**Namespace:** ratio of the total comment lines of the namespace (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). - -**Component:** ratio of the total comment lines of the component (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). - #### Total Comment Lines of Code (TCLOC) {#TCLOC} **Method:** number of comment and documentation code lines of the method, including its anonymous classes. @@ -272,12 +218,6 @@ The following table summarizes the metrics, their abbreviations and their corres **File:** number of non-empty and non-comment code lines of the file. -#### Number of Attributes (NA) {#NA} - -**Class, Structure:** number of attributes in the class, including the inherited ones and generated ones backing auto properties; however, the attributes of its nested and anonymous classes are not included. - -**Namespace:** number of attributes in the namespace; however, attributes of its subnamespaces are not included. - #### Number of Classes (NCL) {#NCL} **Namespace:** number of classes in the namespace; however, the classes of its subnamespaces are not included. @@ -296,10 +236,6 @@ The following table summarizes the metrics, their abbreviations and their corres **Namespace:** number of interfaces in the namespace; however, the interfaces of its subnamespaces are not included. -#### Number of Local Attributes (NLA) {#NLA} - -**Class, Structure:** number of local (i.e. not inherited) attributes in the class, including generated ones backing auto properties; however, the attributes of nested and anonymous classes are not included. - #### Number of Local Getters (NLG) {#NLG} **Class, Structure:** number of local (i.e. not inherited) getter methods in the class; however, the getter methods of its nested and anonymous classes are not included. Methods that override abstract methods are not counted. @@ -308,10 +244,6 @@ The following table summarizes the metrics, their abbreviations and their corres **Class, Structure:** number of local (i.e. not inherited) methods in the class; however, the methods of nested and anonymous classes are not included. -#### Number of Local Public Attributes (NLPA) {#NLPA} - -**Class, Structure:** number of local (i.e. not inherited) public attributes in the class, including generated ones backing public auto properties; however, the attributes of nested and anonymous classes are not included. - #### Number of Local Public Methods (NLPM) {#NLPM} **Class, Structure:** number of local (i.e. not inherited) public methods in the class; however, the methods of nested and anonymous classes are not included. @@ -334,12 +266,6 @@ The following table summarizes the metrics, their abbreviations and their corres **Method:** number of the parameters of the method. The varargs parameter counts as one. -#### Number of Public Attributes (NPA) {#NPA} - -**Class, Structure:** number of public attributes in the class, including the inherited ones and generated ones backing public auto properties; however, the public attributes of its nested and anonymous classes are not included. - -**Namespace:** number of public attributes in the namespace; however, the public attributes of its subnamespaces are not included. - #### Number of Public Methods (NPM) {#NPM} **Class, Structure:** number of public methods in the class, including the inherited ones; however, the public methods of nested and anonymous classes are not included. Methods that override abstract methods are not counted. @@ -382,14 +308,6 @@ The following table summarizes the metrics, their abbreviations and their corres **Component:** number of non-empty and non-comment code lines of the component, including its subcomponents. -#### Total Number of Attributes (TNA) {#TNA} - -**Class, Structure:** number of attributes in the class, including the inherited ones and generated ones backing auto properties, as well as the inherited and local attributes of its nested and anonymous classes. - -**Namespace:** number of attributes in the namespace, including the attributes of its subnamespaces. - -**Component:** number of attributes in the component, including the attributes of its subcomponents. - #### Total Number of Classes (TNCL) {#TNCL} **Namespace:** number of classes in the namespace, including the classes of its subnamespaces. @@ -428,10 +346,6 @@ The following table summarizes the metrics, their abbreviations and their corres **Component:** number of interfaces in the component, including the interfaces of its subcomponents. -#### Total Number of Local Attributes (TNLA) {#TNLA} - -**Class, Structure:** number of local (i.e. not inherited) attributes in the class, including the generated ones backing auto properties and also attributes of its nested and anonymous classes. - #### Total Number of Local Getters (TNLG) {#TNLG} **Class, Structure:** number of local (i.e. not inherited) getter methods in the class, including the local getter methods of its nested and anonymous classes. @@ -440,10 +354,6 @@ The following table summarizes the metrics, their abbreviations and their corres **Class, Structure:** number of local (i.e. not inherited) methods in the class, including the local methods of its nested and anonymous classes. -#### Total Number of Local Public Attributes (TNLPA) {#TNLPA} - -**Class, Structure:** number of local (i.e. not inherited) public attributes in the class, including the generated ones backing public auto properties and also local public attributes of its nested and anonymous classes. - #### Total Number of Local Public Methods (TNLPM) {#TNLPM} **Class, Structure:** number of local (i.e. not inherited) public methods in the class, including the local methods of its nested and anonymous classes. @@ -466,10 +376,6 @@ The following table summarizes the metrics, their abbreviations and their corres **Component:** number of namespaces and subnamespaces that belong to the component, including its subcomponents. -#### Total Number of Public Attributes (TNPA) {#TNPA} - -**Class, Structure:** number of public attributes in the class, including the inherited ones and the generated ones backing public auto properties as well as the inherited and local public attributes of its nested and anonymous classes. - **Namespace:** number of public attributes in the namespace, including the public attributes of its subnamespaces. **Component:** number of public attributes in the component, including the public attributes of its subcomponents. diff --git a/OpenStaticAnalyzer/doc/readme.txt b/OpenStaticAnalyzer/doc/readme.txt index f10e1b4..74ee49b 100644 --- a/OpenStaticAnalyzer/doc/readme.txt +++ b/OpenStaticAnalyzer/doc/readme.txt @@ -1,6 +1,6 @@ OpenStaticAnalyzer is a source code analyzer tool, which can perform deep static analysis of the source code of complex software systems implemented in -Java, Python, JavaScript, or C# programming languages. +Java, Python, JavaScript, C#, or C/C++ programming languages. The source code of a program is usually its only up-to-date documentation. At the same time, the source code is the exquisite bearer of knowledge, business @@ -17,14 +17,14 @@ be improved and developed both in the short- and long term in a directed way. Product characteristics The most important product characteristics of OpenStaticAnalyzer are the following: -* Support for Java 11, Python 2.7.x and 3.8.x, EcmaScript2017 (JavaScript), C# 8.0 +* Support for Java 11, Python 2.7.x and 3.8.x, EcmaScript2022 (JavaScript), C# 8.0, C++17 * Platform-independent command line tools * Transparent integration into build processes * Powerful filter management * Coding issue detection - Common programming mistakes - Metric threshold violations - - Integration of popular free tools (PMD, SpotBugs, Pylint, ESLint, FxCop) + - Integration of popular free tools (PMD, SpotBugs, Pylint, ESLint, FxCop, Cppchek, Clang-Tidy) * Clone detection (copy-pasted source code fragments) extended with clone tracking and "clone smells" - Syntax-based, so-called Type-2 clones @@ -43,4 +43,4 @@ By continuous static analysis, the software developers can: operational risks can be decreased, increasing the company's reputation. For more information about OpenStaticAnalyzer please read the files UsersGuide.html, -which can be found in the Java, Python, JavaScript, and CSharp subdirectories of the package. +which can be found in the Java, Python, JavaScript, CSharp, and CPP subdirectories of the package. diff --git a/OpenStaticAnalyzer/java/CMakeLists.txt b/OpenStaticAnalyzer/java/CMakeLists.txt index f6730b8..7225ea6 100644 --- a/OpenStaticAnalyzer/java/CMakeLists.txt +++ b/OpenStaticAnalyzer/java/CMakeLists.txt @@ -53,9 +53,9 @@ add_custom_generated_copy_dependency_to_tools_dir (PMD2Graph${EXE}) add_custom_generated_copy_dependency_to_tools_dir (PMD.rul PMD2Graph) add_custom_generated_copy_dependency_to_tools_dir (UserDefinedMetrics${EXE}) add_custom_generated_copy_dependency_to_tools_dir (Sonar2Graph${EXE}) -add_custom_generated_copy_dependency_to_tools_dir (LIM2Patterns_java${EXE} LIM2Patterns_java LIM2Patterns${EXE}) -add_custom_generated_copy_dependency_to_tools_dir (Patterns LIM2Patterns_java Patterns DIRECTORY) -add_custom_generated_copy_dependency_to_tools_dir (Lib LIM2Patterns_java Lib DIRECTORY) +add_custom_generated_copy_dependency_to_tools_dir (LIM2Patterns${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (Patterns LIM2Patterns Patterns DIRECTORY) +add_custom_generated_copy_dependency_to_tools_dir (Lib LIM2Patterns Lib DIRECTORY) add_custom_generated_copy_dependency_to_wrapper_tools_dir (GenericConfig${EXE}) add_custom_generated_copy_dependency_to_wrapper_tools_dir (JAN.jar JAN) diff --git a/OpenStaticAnalyzer/java/doc/usersguide/md/Main.md b/OpenStaticAnalyzer/java/doc/usersguide/md/Main.md index 8d45e20..7b59c86 100644 --- a/OpenStaticAnalyzer/java/doc/usersguide/md/Main.md +++ b/OpenStaticAnalyzer/java/doc/usersguide/md/Main.md @@ -194,7 +194,7 @@ Source code elements in the files marked with darker background will not be cons **-runMetricHunter** : This parameter turns on or off the MetricHunter module. With this feature, OpenStaticAnalyzer lists metric threshold violations. Its value can be "true" (turn this feature on) or "false" (turn this feature off). The default value is "true". - + **-runDCF** : This parameter turns on or off the DuplicatedCodeFinder module. With this feature, OpenStaticAnalyzer identifies copy-pasted code fragments. Its value can be "true" (turn this feature on) or "false" (turn this feature off). The default value is "true". @@ -274,7 +274,7 @@ Source code elements in the files marked with darker background will not be cons : The name of the directory with date inside the result directory of the project. If it is not set, then the current date is used. **-cleanResults** - + : Cleans all but the last n number of timestamped result directory of the current project. **-cleanProject** @@ -344,7 +344,7 @@ Source code elements in the files marked with darker background will not be cons **-SQLanguageKey** : The key of the language in SonarQube. - + **-runLIM2Patterns** : This parameter can be used to enable or disable the LIM2Patterns module during analysis (default = on). diff --git a/OpenStaticAnalyzer/java/doc/usersguide/md/SourceCodeMetricsRef.md b/OpenStaticAnalyzer/java/doc/usersguide/md/SourceCodeMetricsRef.md index d997562..7d3beee 100644 --- a/OpenStaticAnalyzer/java/doc/usersguide/md/SourceCodeMetricsRef.md +++ b/OpenStaticAnalyzer/java/doc/usersguide/md/SourceCodeMetricsRef.md @@ -23,35 +23,17 @@ The following table summarizes the metrics, their abbreviations and their corres Category Metric name Abbreviation Annotation Class Component Enum File Interface Method Package ---------------------- -------------------------------------------- ------------- ------------ ------- ----------- ------ ------ ----------- -------- --------- Cohesion metrics Lack of Cohesion in Methods 5 LCOM5 X X X X - Complexity metrics Halstead Calculated Program Length HCPL X - Halstead Difficulty HDIF X - Halstead Effort HEFF X - Halstead Number of Delivered Bugs HNDB X - Halstead Program Length HPL X - Halstead Program Vocabulary HPV X - Halstead Time Required to Program HTRP X - Halstead Volume HVOL X - Maintainability Index (Microsoft version) MIMS X - Maintainability Index (Original version) MI X - Maintainability Index (SEI version) MISEI X - Maintainability Index (OpenStaticAnalyzer version) MISM X - McCabe's Cyclomatic Complexity McCC X X - Nesting Level NL X X X X X - Nesting Level Else-If NLE X X X X X + Complexity metrics McCabe's Cyclomatic Complexity McCC X X Weighted Methods per Class WMC X X X X Coupling metrics Coupling Between Object classes CBO X X X X - Coupling Between Object classes Inverse CBOI X X X X - Number of Incoming Invocations NII X X X X X - Number of Outgoing Invocations NOI X X X X X + Number of Outgoing Invocations NOI X X X X X Response set For Class RFC X X X X Documentation metrics API Documentation AD X X X X X - Comment Density CD X X X X X X - Comment Lines of Code CLOC X X X X X X X + Comment Density CD X X X X X X Documentation Lines of Code DLOC X X X X X Public Documented API PDA X X X X X X Public Undocumented API PUA X X X X X X Total API Documentation TAD X X - Total Comment Density TCD X X X X X X X Total Comment Lines of Code TCLOC X X X X X X X Total Public Documented API TPDA X X Total Public Undocumented API TPUA X X @@ -62,42 +44,34 @@ The following table summarizes the metrics, their abbreviations and their corres Number of Parents NOP X X X X Size metrics Lines of Code LOC X X X X X X X Logical Lines of Code LLOC X X X X X X X - Number of Attributes NA X X X X X Number of Classes NCL X Number of Enums NEN X Number of Getters NG X X X X X Number of Interfaces NIN X - Number of Local Attributes NLA X X X X Number of Local Getters NLG X X X X Number of Local Methods NLM X X X X - Number of Local Public Attributes NLPA X X X X Number of Local Public Methods NLPM X X X X Number of Local Setters NLS X X X X Number of Methods NM X X X X X Number of Packages NPKG X Number of Parameters NUMPAR X - Number of Public Attributes NPA X X X X X Number of Public Methods NPM X X X X X Number of Setters NS X X X X X Number of Statements NOS X X X X X Total Lines of Code TLOC X X X X X X X Total Logical Lines of Code TLLOC X X X X X X X - Total Number of Attributes TNA X X X X X X Total Number of Classes TNCL X X Total Number of Directories TNDI X X Total Number of Enums TNEN X X Total Number of Files TNFI X X Total Number of Getters TNG X X X X X X Total Number of Interfaces TNIN X X - Total Number of Local Attributes TNLA X X X X Total Number of Local Getters TNLG X X X X Total Number of Local Methods TNLM X X X X - Total Number of Local Public Attributes TNLPA X X X X Total Number of Local Public Methods TNLPM X X X X Total Number of Local Setters TNLS X X X X Total Number of Methods TNM X X X X X X Total Number of Packages TNPKG X X - Total Number of Public Attributes TNPA X X X X X X Total Number of Public Classes TNPCL X X Total Number of Public Enums TNPEN X X Total Number of Public Interfaces TNPIN X X @@ -115,153 +89,6 @@ The following table summarizes the metrics, their abbreviations and their corres ### Complexity metrics -#### Halstead Calculated Program Length (HCPL) {#HCPL} - -**Method:** - - * _n1_: number of distinct operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations) - * _n2_: number of distinct operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations) - -The calculated program length is _n1 * log~2~(n1) + n2 * log~2~(n2)_. - - -#### Halstead Difficulty (HDIF) {#HDIF} - -**Method:** - - * _n1_: number of distinct operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations) - * _n2_: number of distinct operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations) - * _N2_: total number of operands - -The Halstead difficulty is _n1/2 * N2/n2_. - - -#### Halstead Effort (HEFF) {#HEFF} - -**Method:** - - * _n1_: number of distinct operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations) - * _n2_: number of distinct operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations) - * _N1_: total number of operators - * _N2_: total number of operands - * _n : n1 + n2_ (program vocabulary) - * _N : N1 + N2_ (program length) - * _V : N * log~2~(n)_ (volume) - * _D : n1/2 * N2/n2_ (difficulty) - -The Halstead effort is _D * V_. - -#### Halstead Number of Delivered Bugs (HNDB) {#HNDB} - -**Method:** - - * _n1_: number of distinct operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations) - * _n2_: number of distinct operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations) - * _N1_: total number of operators - * _N2_: total number of operands - * _n : n1 + n2_ (program vocabulary) - * _N : N1 + N2_ (program length) - * _V : N * log~2~(n)_ (volume) - * _D : n1/2 * N2/n2_ (difficulty) - * _E : D * V_ (effort) - -Number of delivered bugs is _E^2/3^/3000_. - - -#### Halstead Program Length (HPL) {#HPL} - -**Method:** - - * _N1_: total number of operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations) - * _N2_: total number of operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations) - -Halstead program length is _N1 + N2_. - - -#### Halstead Program Vocabulary (HPV) {#HPV} - -**Method:** - - * _n1_: number of distinct operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations) - * _n2_: number of distinct operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations) - -Halstead program vocabulary is _n1 + n2_. - - -#### Halstead Time Required to Program (HTRP) {#HTRP} - -**Method:** - - * _n1_: number of distinct operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations) - * _n2_: number of distinct operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations) - * _N1_: total number of operators - * _N2_: total number of operands - * _n : n1 + n2_ (program vocabulary) - * _N : N1 + N2_ (program length) - * _V : N * log~2~(n)_ (volume) - * _D : n1/2 * N2/n2_ (difficulty) - * _E : D * V_ (effort) - -Halstead time required to program is _E/18_ seconds. - - -#### Halstead Volume (HVOL) {#HVOL} - -**Method:** - - * _n1_: number of distinct operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations) - * _n2_: number of distinct operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations) - * _N1_: total number of operators - * _N2_: total number of operands - * _n : n1 + n2_ (program vocabulary) - * _N : N1 + N2_ (program length) - -The Halstead volume is _N * log~2~(n)_. - - -#### Maintainability Index (Microsoft version) (MIMS) {#MIMS} - - * _HVOL_: Halstead Volume - * _McCC_: McCabe's cyclomatic complexity - * _LLOC_: logical lines of code - -The Maintainability Index used by Microsoft's Visual Studio is computed by the following formula: - -_MIMS = max(0,(171 - 5.2 * ln(HVOL) - 0.23 * (McCC) - 16.2 * ln(LLOC)) * 100 / 171)_ - -#### Maintainability Index (Original version) (MI) {#MI} - - * _HVOL_: Halstead Volume - * _McCC_: McCabe's cyclomatic complexity - * _LLOC_: logical lines of code - -The original Maintainability Index is computed by the following formula: - -_MI = 171 - 5.2 * ln(HVOL) - 0.23 * (McCC) - 16.2 * ln(LLOC)_ - -#### Maintainability Index (SEI version) (MISEI) {#MISEI} - - * _HVOL_: Halstead Volume - * _McCC_: McCabe's cyclomatic complexity - * _LLOC_: logical lines of code - * _CD_: comment density - -The Maintainability Index derived by the Software Engineering Institute (SEI) is computed by the following formula: - -_MISEI = 171 - 5.2 * log~2~(HVOL) - 0.23 * McCC - 16.2 * log~2~(LLOC) + 50 * sin(sqrt(2.4 * CD))_ - -#### Maintainability Index (OpenStaticAnalyzer version) (MISM) {#MISM} - - * _HVOL_: Halstead Volume - * _McCC_: McCabe's cyclomatic complexity - * _LLOC_: logical lines of code - * _CD_: comment density - -The Maintainability Index proposed by OpenStaticAnalyzer combines the different scaling approach from Microsoft's version with the inclusion of comment percentage from the Software Engineering Institute (SEI) version into the following formula: - -_MISM = max(0, (171 - 5.2 * log~2~(HVOL) - 0.23 * McCC - 16.2 * log~2~(LLOC) + 50 * sin(sqrt(2.4 * CD))) * 100 / 171)_ - - #### McCabe's Cyclomatic Complexity (McCC) {#McCC} **Method:** complexity of the method expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, for, foreach, while, do-while, case label (which belongs to a switch instruction), catch, conditional statement (?:). Moreover, logical "and" (&&) and logical "or" (||) expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, switch, default label (which belongs to a switch instruction), try, finally. @@ -269,20 +96,6 @@ _MISM = max(0, (171 - 5.2 * log~2~(HVOL) - 0.23 * McCC - 16.2 * log~2~(LLOC) + 5 **File:** complexity of the file expressed as the number of independent control flow paths in it. It is calculated as the sum of the McCabe's Cyclomatic Complexity values of the methods can be found in the file. -#### Nesting Level (NL) {#NL} - -**Method:** complexity of the method expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes. The following instructions are taken into account: if, else-if, else, for, while, do-while, switch, try, catch, finally and block statements that are directly inside another block statement. The following instructions do not increase the value by themselves; however, if additional embeddednesses can be found in their blocks, they are considered: case and default label (which belong to a switch instruction). - -**Class:** complexity of the class expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes. It is calculated as the maximum nesting level (NL) of its local methods and init blocks. - - -#### Nesting Level Else-If (NLE) {#NLE} - -**Method:** complexity of the method expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes, where in the if-else-if construct only the first if instruction is considered. The following instructions are taken into account: if, else, for, while, do-while, switch, try, catch, finally and block statements that are directly inside another block statement. The following instructions do not increase the value by themselves; however, if additional embeddednesses can be found in their blocks, they are considered: else-if (i.e. in the if-else-if construct the use of else-if does not increase the value of the metric), case and default label (which belong to a switch instruction). - -**Class:** complexity of the class expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes, where in the if-else-if construct only the first if instruction is considered. It is calculated as the maximum nesting level (NLE) of its local methods and init blocks. - - #### Weighted Methods per Class (WMC) {#WMC} **Class:** complexity of the class expressed as the number of independent control flow paths in it. It is calculated as the sum of the McCabe's Cyclomatic Complexity (McCC) values of its local methods and init blocks. @@ -295,18 +108,6 @@ _MISM = max(0, (171 - 5.2 * log~2~(HVOL) - 0.23 * McCC - 16.2 * log~2~(LLOC) + 5 **Class:** number of directly used other classes (e.g. by inheritance, function call, type reference, attribute reference). Classes using many other classes highly depend on their environment, so it is difficult to test or reuse them; furthermore, they are very sensitive to the changes in the system. -#### Coupling Between Object classes Inverse (CBOI) {#CBOI} - -**Class:** number of other classes, which directly use the class. Classes which are used by many other classes have a high impact on the behavior of the system, and should be modified very carefully and tested intensively. - - -#### Number of Incoming Invocations (NII) {#NII} - -**Method:** number of other methods and attribute initializations which directly call the method. If the method is invoked several times from the same method or attribute initialization, it is counted only once. - -**Class:** number of other methods and attribute initializations which directly call the local methods of the class. If a method is invoked several times from the same method or attribute initialization, it is counted only once. - - #### Number of Outgoing Invocations (NOI) {#NOI} **Method:** number of directly called methods. If a method is invoked several times, it is counted only once. @@ -328,15 +129,6 @@ _MISM = max(0, (171 - 5.2 * log~2~(HVOL) - 0.23 * McCC - 16.2 * log~2~(LLOC) + 5 **Package:** ratio of the number of documented public classes and methods in the package to the number of all of its public classes and methods; however, the classes and methods of its subpackages are not included. -#### Comment Density (CD) {#CD} - -**Method:** ratio of the comment lines of the method (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC). - -**Class**: ratio of the comment lines of the class (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC). - -**Package:** ratio of the comment lines of the package (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC). - - #### Comment Lines of Code (CLOC) {#CLOC} **Method**: number of comment and documentation code lines of the method; however, its anonymous and local classes are not included. @@ -380,17 +172,6 @@ _MISM = max(0, (171 - 5.2 * log~2~(HVOL) - 0.23 * McCC - 16.2 * log~2~(LLOC) + 5 **Component:** ratio of the number of documented public classes and methods in the component to the number of all of its public classes and methods, including its subcomponents. -#### Total Comment Density (TCD) {#TCD} - -**Method:** ratio of the total comment lines of the method (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). - -**Class:** ratio of the total comment lines of the class (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). - -**Package:** ratio of the total comment lines of the package (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). - -**Component:** ratio of the total comment lines of the component (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). - - #### Total Comment Lines of Code (TCLOC) {#TCLOC} **Method**: number of comment and documentation code lines of the method, including its anonymous and local classes. @@ -468,13 +249,6 @@ _MISM = max(0, (171 - 5.2 * log~2~(HVOL) - 0.23 * McCC - 16.2 * log~2~(LLOC) + 5 -#### Number of Attributes (NA) {#NA} - -**Class:** number of attributes in the class, including the inherited ones; however, the attributes of its nested, anonymous, and local classes are not included. - -**Package:** number of attributes in the package; however, attributes of its subpackages are not included. - - #### Number of Classes (NCL) {#NCL} **Package:** number of classes in the package; however, the classes of its subpackages are not included. @@ -497,11 +271,6 @@ _MISM = max(0, (171 - 5.2 * log~2~(HVOL) - 0.23 * McCC - 16.2 * log~2~(LLOC) + 5 **Package:** number of interfaces in the package; however, the interfaces of its subpackages are not included. -#### Number of Local Attributes (NLA) {#NLA} - -**Class:** number of local (i.e. not inherited) attributes in the class; however, the attributes of nested, anonymous, and local classes are not included. - - #### Number of Local Getters (NLG) {#NLG} **Class:** number of local (i.e. not inherited) getter methods in the class; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted. @@ -512,11 +281,6 @@ _MISM = max(0, (171 - 5.2 * log~2~(HVOL) - 0.23 * McCC - 16.2 * log~2~(LLOC) + 5 **Class:** number of local (i.e. not inherited) methods in the class; however, the methods of nested, anonymous, and local classes are not included. -#### Number of Local Public Attributes (NLPA) {#NLPA} - -**Class:** number of local (i.e. not inherited) public attributes in the class; however, the attributes of nested, anonymous, and local classes are not included. - - #### Number of Local Public Methods (NLPM) {#NLPM} **Class:** number of local (i.e. not inherited) public methods in the class; however, the methods of nested, anonymous, and local classes are not included. @@ -544,13 +308,6 @@ _MISM = max(0, (171 - 5.2 * log~2~(HVOL) - 0.23 * McCC - 16.2 * log~2~(LLOC) + 5 **Method**: number of the parameters of the method. The varargs parameter counts as one. -#### Number of Public Attributes (NPA) {#NPA} - -**Class:** number of public attributes in the class, including the inherited ones; however, the public attributes of its nested, anonymous, and local classes are not included. - -**Package:** number of public attributes in the package; however, the public attributes of its subpackages are not included. - - #### Number of Public Methods (NPM) {#NPM} **Class:** number of public methods in the class, including the inherited ones; however, the public methods of nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted. @@ -594,15 +351,6 @@ _MISM = max(0, (171 - 5.2 * log~2~(HVOL) - 0.23 * McCC - 16.2 * log~2~(LLOC) + 5 **Component:** number of non-empty and non-comment code lines of the component, including its subcomponents. -#### Total Number of Attributes (TNA) {#TNA} - -**Class:** number of attributes in the class, including the inherited ones, as well as the inherited and local attributes of its nested, anonymous and local classes. - -**Package:** number of attributes in the package, including the attributes of its subpackages. - -**Component:** number of attributes in the component, including the attributes of its subcomponents. - - #### Total Number of Classes (TNCL) {#TNCL} **Package:** number of classes in the package, including the classes of its subpackages. @@ -647,11 +395,6 @@ _MISM = max(0, (171 - 5.2 * log~2~(HVOL) - 0.23 * McCC - 16.2 * log~2~(LLOC) + 5 **Component:** number of interfaces in the component, including the interfaces of its subcomponents. -#### Total Number of Local Attributes (TNLA) {#TNLA} - -**Class:** number of local (i.e. not inherited) attributes in the class, including the attributes of its nested, anonymous, and local classes. - - #### Total Number of Local Getters (TNLG) {#TNLG} **Class:** number of local (i.e. not inherited) getter methods in the class, including the local getter methods of its nested, anonymous, and local classes. @@ -662,11 +405,6 @@ _MISM = max(0, (171 - 5.2 * log~2~(HVOL) - 0.23 * McCC - 16.2 * log~2~(LLOC) + 5 **Class:** number of local (i.e. not inherited) methods in the class, including the local methods of its nested, anonymous, and local classes. -#### Total Number of Local Public Attributes (TNLPA) {#TNLPA} - -**Class:** number of local (i.e. not inherited) public attributes in the class, including the local public attributes of its nested, anonymous, and local classes. - - #### Total Number of Local Public Methods (TNLPM) {#TNLPM} **Class:** number of local (i.e. not inherited) public methods in the class, including the local methods of its nested, anonymous, and local classes. @@ -693,15 +431,6 @@ _MISM = max(0, (171 - 5.2 * log~2~(HVOL) - 0.23 * McCC - 16.2 * log~2~(LLOC) + 5 **Component:** number of packages and subpackages that belong to the component, including its subcomponents. -#### Total Number of Public Attributes (TNPA) {#TNPA} - -**Class:** number of public attributes in the class, including the inherited ones, as well as the inherited and local public attributes of its nested, anonymous, and local classes. - -**Package:** number of public attributes in the package, including the public attributes of its subpackages. - -**Component:** number of public attributes in the component, including the public attributes of its subcomponents. - - #### Total Number of Public Classes (TNPCL) {#TNPCL} **Package:** number of public classes in the package, including the public classes of its subpackages. diff --git a/OpenStaticAnalyzer/javascript/CMakeLists.txt b/OpenStaticAnalyzer/javascript/CMakeLists.txt index fe7bffd..5f3e9a8 100644 --- a/OpenStaticAnalyzer/javascript/CMakeLists.txt +++ b/OpenStaticAnalyzer/javascript/CMakeLists.txt @@ -31,11 +31,12 @@ add_custom_generated_copy_dependency_to_tools_dir (GraphMerge${EXE}) add_custom_generated_copy_dependency_to_tools_dir (JSAN2Lim${EXE}) #copy JSAN and ESlintRunner -add_custom_generated_copy_dependency (${OSA_TARGET_NAME} ${EXECUTABLE_OUTPUT_PATH}/node_modules ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/Tools/node_modules jsan JSAN jsan DIRECTORY) -add_custom_generated_copy_dependency (${OSA_TARGET_NAME} ${EXECUTABLE_OUTPUT_PATH}/node_modules ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/Tools/node_modules eslintrunner ESLintRunner eslintrunner DIRECTORY) +add_custom_generated_copy_dependency (${OSA_TARGET_NAME} ${EXECUTABLE_OUTPUT_PATH}/node_modules ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/Tools/node_modules jsan JSAN_virtual_target jsan DIRECTORY) +add_custom_generated_copy_dependency (${OSA_TARGET_NAME} ${EXECUTABLE_OUTPUT_PATH}/node_modules ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/Tools/node_modules eslintrunner eslintrunner_virtual_target eslintrunner DIRECTORY) add_custom_generated_copy_dependency_to_tools_dir (rules_javascript.csv OpenStaticAnalyzerJavaScript) add_custom_generated_copy_dependency_to_tools_dir (ESLint.rul ESLint2Graph_copy_ESLint.rul) +add_custom_generated_copy_dependency_to_tools_dir (TSLint.rul ESLint2Graph_copy_ESLint.rul TSLint.rul) add_custom_generated_copy_dependency_to_tools_dir (JSAN2ChangePath${EXE}) add_custom_generated_copy_dependency_to_tools_dir (ESLint2Graph${EXE}) add_custom_generated_copy_dependency_to_tools_dir (LIM2Metrics${EXE}) @@ -46,9 +47,9 @@ add_custom_generated_copy_dependency_to_tools_dir (MetricHunter_javascript${EXE} add_custom_generated_copy_dependency_to_tools_dir (MetricHunter_JAVASCRIPT.threshold MetricHunter_javascript_copy_MetricHunter_JAVASCRIPT.threshold MetricHunter.threshold) add_custom_generated_copy_dependency_to_tools_dir (UserDefinedMetrics${EXE}) add_custom_generated_copy_dependency_to_tools_dir (Sonar2Graph${EXE}) -add_custom_generated_copy_dependency_to_tools_dir (LIM2Patterns_javascript${EXE} LIM2Patterns_javascript LIM2Patterns${EXE}) -add_custom_generated_copy_dependency_to_tools_dir (Patterns LIM2Patterns_javascript Patterns DIRECTORY) -add_custom_generated_copy_dependency_to_tools_dir (Lib LIM2Patterns_javascript Lib DIRECTORY) +add_custom_generated_copy_dependency_to_tools_dir (LIM2Patterns${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (Patterns LIM2Patterns Patterns DIRECTORY) +add_custom_generated_copy_dependency_to_tools_dir (Lib LIM2Patterns Lib DIRECTORY) #user's guide add_custom_generated_copy_dependency( diff --git a/OpenStaticAnalyzer/javascript/doc/usersguide/md/ESLintRef.md b/OpenStaticAnalyzer/javascript/doc/usersguide/md/ESLintRef.md index 9d5006e..3c7ab53 100644 --- a/OpenStaticAnalyzer/javascript/doc/usersguide/md/ESLintRef.md +++ b/OpenStaticAnalyzer/javascript/doc/usersguide/md/ESLintRef.md @@ -1,76 +1,119 @@ -## Reference of ESLint coding rule violations - -OpenStaticAnalyzer incorporates the [ESLint] tool for coding rule violation checking and imports its results. OpenStaticAnalyzer also associates the issued rule violations with source code elements (i.e. methods, classes, functions, and components), and calculates metrics for the source code elements, which represent the amount of violations of each ruleset, rule, and priority groups, respectively. - -OpenStaticAnalyzer uses ESLint "as is", without any guaranties that the results of ESLint are correct. All statements of the ESLint license apply here as well. All texts describing the rulesets and the individual rules are copied from its official home page with some minor grammatical fixes. +## Reference of TSLINT coding rule violations The list of rulesets and rules contained in each ruleset are the following: - **Best Practices:** These are rules designed to prevent you from making mistakes. They either prescribe a better way of doing something or help you avoid footguns. + - **ECMAScript 6:** These rules are only relevant to ES6 environments. + - **Possible Errors:** These rules relate to possible syntax or logic errors in JavaScript code. + - **Stylistic Issues:** These rules are purely matters of style and are quite subjective. + +- **TS Best Practices:** These are rules designed to prevent you from making mistakes in TypeScript. They either prescribe a better way of doing something or help you avoid footguns. + + +- **TS Possible Errors:** These rules relate to possible syntax or logic errors in TypeScript code. + + +- **TS Variables:** These rules have to do with variable declarations within TypeScript. + + - **Variables:** These rules have to do with variable declarations. + The following table contains the enabled rules and their priorities: - Category Name Abbreviation Prio. - ----------------- ------------------------- ------------- ------ - Best Practices eqeqeq ESLINT_E Major - no-case-declarations ESLINT_NCD Major - no-empty-pattern ESLINT_NEPA Major - no-fallthrough ESLINT_NF Major - no-global-assign ESLINT_NGA Major - no-iterator ESLINT_NI Major - no-magic-numbers ESLINT_NMN Major - no-new-wrappers ESLINT_NNW Major - no-octal ESLINT_NO Major - no-redeclare ESLINT_NR Major - no-self-assign ESLINT_NSAS Major - no-unused-labels ESLINT_NULA Major - no-useless-escape ESLINT_NUES Major - ECMAScript 6 constructor-super ESLINT_CSU Major - no-class-assign ESLINT_NCAS Major - no-const-assign ESLINT_NCONS Major - no-dupe-class-members ESLINT_NDCM Major - no-new-symbol ESLINT_NNSY Major - no-this-before-super ESLINT_NTBS Major - require-yield ESLINT_RY Major - Possible Errors no-compare-neg-zero ESLINT_NCNZ Major - no-cond-assign ESLINT_NCA Major - no-console ESLINT_NC Major - no-constant-condition ESLINT_NCC Major - no-control-regex ESLINT_NCR Major - no-debugger ESLINT_ND Major - no-dupe-args ESLINT_NDA Major - no-dupe-keys ESLINT_NDK Major - no-duplicate-case ESLINT_NDC Major - no-empty ESLINT_NE Major - no-empty-character-class ESLINT_NECC Major - no-ex-assign ESLINT_NEA Major - no-extra-boolean-cast ESLINT_NEBC Major - no-extra-semi ESLINT_NES Major - no-func-assign ESLINT_NFA Major - no-inner-declarations ESLINT_NID Major - no-invalid-regexp ESLINT_NIR Major - no-irregular-whitespace ESLINT_NIW Major - no-obj-calls ESLINT_NOC Major - no-regex-spaces ESLINT_NRS Major - no-sparse-arrays ESLINT_NSA Major - no-unexpected-multiline ESLINT_NUM Major - no-unreachable ESLINT_NU Major - no-unsafe-finally ESLINT_NUF Major - no-unsafe-negation ESLINT_NUNEG Major - use-isnan ESLINT_UI Major - valid-typeof ESLINT_VT Major - Stylistic Issues no-mixed-spaces-and-tabs ESLINT_NMSAT Major - Variables no-delete-var ESLINT_NDV Major - no-undef ESLINT_NUN Major - no-unused-vars ESLINT_NUV Major + Category Name Abbreviation Prio. + ------------------- ---------------------------------------- -------------- ------ + Best Practices eqeqeq ESLINT_E Major + no-case-declarations ESLINT_NCD Major + no-empty-pattern ESLINT_NEPA Major + no-fallthrough ESLINT_NF Major + no-global-assign ESLINT_NGA Major + no-iterator ESLINT_NI Major + no-new-wrappers ESLINT_NNW Major + no-octal ESLINT_NO Major + no-self-assign ESLINT_NSAS Major + no-unused-labels ESLINT_NULA Major + no-useless-escape ESLINT_NUES Major + ECMAScript 6 constructor-super ESLINT_CSU Major + no-class-assign ESLINT_NCAS Major + no-const-assign ESLINT_NCONS Major + no-new-symbol ESLINT_NNSY Major + no-this-before-super ESLINT_NTBS Major + require-yield ESLINT_RY Major + Possible Errors no-compare-neg-zero ESLINT_NCNZ Major + no-cond-assign ESLINT_NCA Major + no-console ESLINT_NC Major + no-constant-condition ESLINT_NCC Major + no-control-regex ESLINT_NCR Major + no-debugger ESLINT_ND Major + no-dupe-args ESLINT_NDA Major + no-dupe-keys ESLINT_NDK Major + no-duplicate-case ESLINT_NDC Major + no-empty ESLINT_NE Major + no-empty-character-class ESLINT_NECC Major + no-ex-assign ESLINT_NEA Major + no-extra-boolean-cast ESLINT_NEBC Major + no-func-assign ESLINT_NFA Major + no-inner-declarations ESLINT_NID Major + no-invalid-regexp ESLINT_NIR Major + no-irregular-whitespace ESLINT_NIW Major + no-obj-calls ESLINT_NOC Major + no-regex-spaces ESLINT_NRS Major + no-sparse-arrays ESLINT_NSA Major + no-unexpected-multiline ESLINT_NUM Major + no-unreachable ESLINT_NU Major + no-unsafe-finally ESLINT_NUF Major + no-unsafe-negation ESLINT_NUNEG Major + use-isnan ESLINT_UI Major + valid-typeof ESLINT_VT Major + Stylistic Issues adjacent-overload-signatures TSLINT_AOS Major + array-type TSLINT_AT Major + no-mixed-spaces-and-tabs ESLINT_NMSAT Major + no-var-requires TSLINT_NVR Major + unified-signatures TSLINT_US Major + TS Best Practices await-thenable TSLINT_ATH Major + ban-ts-comment TSLINT_BTC Major + ban-types TSLINT_BT Major + no-explicit-any TSLINT_NEA Major + no-extra-non-null-assertion TSLINT_NENNA Major + no-magic-numbers TSLINT_NMN Major + no-namespace TSLINT_NN Major + no-non-null-asserted-nullish-coalescing TSLINT_NNNANC Major + no-redeclare TSLINT_NR Major + prefer-namespace-keyword TSLINT_PNK Major + triple-slash-reference TSLINT_TSR Major + unbound-method TSLINT_UM Major + TS Possible Errors no-dupe-class-members TSLINT_NDCM Major + no-empty-interface TSLINT_NEI Major + no-extra-parens TSLINT_NEP Major + no-extra-semi TSLINT_NES Major + no-floating-promises TSLINT_NFP Major + no-for-in-array TSLINT_NFIA Major + no-implicit-any-catch TSLINT_NIAC Major + no-misused-promises TSLINT_NMP Major + no-non-null-asserted-optional-chain TSLINT_NNNAOC Major + no-unsafe-argument TSLINT_NUA Major + no-unsafe-assignment TSLINT_NUAS Major + no-unsafe-call TSLINT_NUCA Major + no-unsafe-member-access TSLINT_NUMA Major + no-unsafe-return TSLINT_NUR Major + prefer-as-const TSLINT_PAC Major + restrict-plus-operands TSLINT_RPO Major + TS Variables no-misused-new TSLINT_NMW Major + no-this-alias TSLINT_NTA Major + no-unnecessary-type-arguments TSLINT_NUTA Major + no-unnecessary-type-assertion TSLINT_NUTAS Major + no-unnecessary-type-constraint TSLINT_NUTC Major + no-unused-vars TSLINT_NUV Major + Variables no-delete-var ESLINT_NDV Major + no-undef ESLINT_NUN Major ### Best Practices @@ -95,11 +138,7 @@ JavaScript environments contain a number of built-in global variables, such as w #### no-iterator {#ESLINT_NI} -The iterator property was a SpiderMonkey extension to JavaScript that could be used to create custom iterators that are compatible with JavaScript’s for in and for each constructs. However, this property is now obsolete, so it should not be used. Here’s an example of how this used to work: You should use ECMAScript 6 iterators and generators instead. - - -#### no-magic-numbers {#ESLINT_NMN} -‘Magic numbers’ are numbers that occur multiple time in code without an explicit meaning. They should preferably be replaced by named constants. +The iterator property was a SpiderMonkey extension to JavaScript that could be used to create custom iterators that are compatible with JavaScript’s for in and for each constructs. However, this property is now obsolete, so it should not be used. Here’s an example of how this used to work: You should use ECMAScript 6 iterators and generators instead. #### no-new-wrappers {#ESLINT_NNW} @@ -110,10 +149,6 @@ There are three primitive types in JavaScript that have wrapper objects: string, Octal literals are numerals that begin with a leading zero, such as: The leading zero to identify an octal literal has been a source of confusion and error in JavaScript. ECMAScript 5 deprecates the use of octal numeric literals in JavaScript and octal literals cause syntax errors in strict mode. It’s therefore recommended to avoid using octal literals in JavaScript code. -#### no-redeclare {#ESLINT_NR} -In JavaScript, it’s possible to redeclare the same variable name using var. This can lead to confusion as to where the variable is actually declared and initialized. - - #### no-self-assign {#ESLINT_NSAS} Self assignments have no effect, so probably those are an error due to incomplete refactoring. Those indicate that what you should do is still remaining. @@ -131,29 +166,33 @@ Escaping non-special characters in strings, template literals, and regular expre #### constructor-super {#ESLINT_CSU} Constructors of derived classes must call super(). Constructors of non derived classes must not call super(). If this is not observed, the javascript engine will raise a runtime error. This rule checks whether or not there is a valid super() call. + #### no-class-assign {#ESLINT_NCAS} ClassDeclaration creates a variable, and we can modify the variable. But the modification is a mistake in most cases. + #### no-const-assign {#ESLINT_NCONS} We cannot modify variables that are declared using const keyword. It will raise a runtime error. Under non ES2015 environment, it might be ignored merely. -#### no-dupe-class-members {#ESLINT_NDCM} -If there are declarations of the same name in class members, the last declaration overwrites other declarations silently. It can cause unexpected behaviors. #### no-new-symbol {#ESLINT_NNSY} Using a single import statement per module will make the code clearer because you can see everything being imported from that module on one line. In the following example the module import on line 1 is repeated on line 3. These can be combined to make the list of imports more succinct. + #### no-this-before-super {#ESLINT_NTBS} In the constructor of derived classes, if this/super are used before super() calls, it raises a reference error. This rule checks this/super keywords in constructors, then reports those that are before super(). + #### require-yield {#ESLINT_RY} This rule generates warnings for generator functions that do not have the yield keyword. + ### Possible Errors #### no-compare-neg-zero {#ESLINT_NCNZ} The rule should warn against code that tries to compare against -0, since that will not work as intended. That is, code like x === -0 will pass for both +0 and -0. The author probably intended Object.is(x, -0). + #### no-cond-assign {#ESLINT_NCA} In conditional statements, it is very easy to mistype a comparison operator (such as ==) as an assignment operator (such as =). For example: There are valid reasons to use assignment operators in conditional statements. However, it can be difficult to tell whether a specific assignment was intentional. @@ -202,10 +241,6 @@ If a catch clause in a try statement accidentally (or purposely) assigns another In contexts such as an if statement’s test where the result of the expression will already be coerced to a Boolean, casting to a Boolean via double negation (!!) is unnecessary. For example, these if statements are equivalent: -#### no-extra-semi {#ESLINT_NES} -Typing mistakes and misunderstandings about where semicolons are required can lead to semicolons that are unnecessary. While not technically an error, extra semicolons can cause confusion when reading code. - - #### no-func-assign {#ESLINT_NFA} JavaScript functions can be written as a FunctionDeclaration function foo() { … } or as a FunctionExpression var foo = function() { … };. While a JavaScript interpreter might tolerate it, overwriting/reassigning a function written as a FunctionDeclaration is often indicative of a mistake or issue. @@ -260,10 +295,168 @@ For a vast majority of use-cases, the only valid results of the typeof operator ### Stylistic Issues +#### adjacent-overload-signatures {#TSLINT_AOS} +This rule aims to standardize the way overloaded members are organized. + + +#### array-type {#TSLINT_AT} +This rule aims to standardize usage of array types within your codebase. + + #### no-mixed-spaces-and-tabs {#ESLINT_NMSAT} Most code conventions require either tabs or spaces be used for indentation. As such, it’s usually an error if a single line of code is indented with both tabs and spaces. +#### no-var-requires {#TSLINT_NVR} +Disallows the use of require statements except in import statements. In other words, the use of forms such as var foo = require("foo") are banned. Instead use ES6 style imports or import foo = require("foo") imports. + + +#### unified-signatures {#TSLINT_US} +This rule aims to keep the source code as maintainable as possible by reducing the amount of overloads. + + +### TS Best Practices + +#### await-thenable {#TSLINT_ATH} +Disallows awaiting a value that is not a Thenable. This rule disallows awaiting a value that is not a "Thenable" (an object which has then method, such as a Promise). While it is valid JavaScript to await a non-Promise-like value (it will resolve immediately), this pattern is often a programmer error, such as forgetting to add parenthesis to call a function that returns a Promise. + + +#### ban-ts-comment {#TSLINT_BTC} +This rule lets you set which directive comments you want to allow in your codebase. By default, only @ts-check is allowed, as it enables rather than suppresses errors. + + +#### ban-types {#TSLINT_BT} +This rule bans specific types and can suggest alternatives. Note that it does not ban the corresponding runtime objects from being used. + + +#### no-explicit-any {#TSLINT_NEA} +This rule doesn't allow any types to be defined. It aims to keep TypeScript maximally useful. TypeScript has a compiler flag for --noImplicitAny that will prevent an any type from being implied by the compiler, but doesn't prevent any from being explicitly used. + + +#### no-extra-non-null-assertion {#TSLINT_NENNA} +Disallow extra non-null assertion. + + +#### no-magic-numbers {#TSLINT_NMN} +This rule extends the base eslint/no-magic-numbers rule. It adds support for: numeric literal types, enum members, and readonly class properties. + + +#### no-namespace {#TSLINT_NN} +This rule aims to standardize the way modules are declared. + + +#### no-non-null-asserted-nullish-coalescing {#TSLINT_NNNANC} +The nullish coalescing operator is designed to provide a default value when dealing with null or undefined. Using non-null assertions in the left operand of the nullish coalescing operator is redundant. + + +#### no-redeclare {#TSLINT_NR} +This rule extends the base eslint/no-redeclare rule. It adds support for TypeScript function overloads, and declaration merging. + + +#### prefer-namespace-keyword {#TSLINT_PNK} +This rule aims to standardize the way modules are declared. + + +#### triple-slash-reference {#TSLINT_TSR} +Sets preference level for triple slash directives versus ES6-style import declarations. + + +#### unbound-method {#TSLINT_UM} +Warns when a method is used outside of a method call. + + +### TS Possible Errors + +#### no-dupe-class-members {#TSLINT_NDCM} +This rule extends the base eslint/no-dupe-class-members rule. It adds support for TypeScript's method overload definitions. + + +#### no-empty-interface {#TSLINT_NEI} +This rule aims to ensure that only meaningful interfaces are declared in the code. + + +#### no-extra-parens {#TSLINT_NEP} +This rule extends the base eslint/no-extra-parens rule. It adds support for TypeScript type assertions. + + +#### no-extra-semi {#TSLINT_NES} +This rule extends the base eslint/no-extra-semi rule. It adds support for class properties. + + +#### no-floating-promises {#TSLINT_NFP} +Requires Promise-like values to be handled appropriately. This rule forbids usage of Promise-like values in statements without handling their errors appropriately. Unhandled promises can cause several issues, such as improperly sequenced operations, ignored Promise rejections and more. Valid ways of handling a Promise-valued statement include awaiting, returning, and either calling .then() with two arguments or .catch() with one argument. + + +#### no-for-in-array {#TSLINT_NFIA} +A for-in loop (for (var k in o)) iterates over the properties of an Object. While it is legal to use for-in loops with array types, it is not common. for-in will iterate over the indices of the array as strings, omitting any "holes" in the array. More common is to use for-of, which iterates over the values of an array. + + +#### no-implicit-any-catch {#TSLINT_NIAC} +This rule requires an explicit type to be declared on a catch clause variable. + + +#### no-misused-promises {#TSLINT_NMP} +This rule forbids using promises in places where the TypeScript compiler allows them but they are not handled properly. These situations can often arise due to a missing await keyword or just a misunderstanding of the way async functions are handled/awaited. + + +#### no-non-null-asserted-optional-chain {#TSLINT_NNNAOC} +Optional chain expressions are designed to return undefined if the optional property is nullish. Using non-null assertions after an optional chain expression is wrong, and introduces a serious type safety hole into your code. + + +#### no-unsafe-argument {#TSLINT_NUA} +This rule disallows calling a function with any in its arguments, and it will disallow spreading any[]. This rule also disallows spreading a tuple type with one of its elements typed as any. This rule also compares the argument's type to the variable's type to ensure you don't pass an unsafe any in a generic position to a receiver that's expecting a specific type. For example, it will error if you assign Set any to an argument declared as Set string. + + +#### no-unsafe-assignment {#TSLINT_NUAS} +This rule disallows assigning any to a variable, and assigning any[] to an array destructuring. This rule also compares the assigned type to the variable's type to ensure you don't assign an unsafe any in a generic position to a receiver that's expecting a specific type. For example, it will error if you assign Set any to a variable declared as Set string. + + +#### no-unsafe-call {#TSLINT_NUCA} +This rule disallows calling any variable that is typed as any. + + +#### no-unsafe-member-access {#TSLINT_NUMA} +This rule disallows member access on any variable that is typed as any. + + +#### no-unsafe-return {#TSLINT_NUR} +This rule disallows returning any or any[] from a function. This rule also compares the return type to the function's declared/inferred return type to ensure you don't return an unsafe any in a generic position to a receiver that's expecting a specific type. For example, it will error if you return Set any from a function declared as returning Set string. + + +#### prefer-as-const {#TSLINT_PAC} +This rule recommends usage of const assertion when type primitive value is equal to type. + + +#### restrict-plus-operands {#TSLINT_RPO} +When adding two variables, operands must both be of type number or of type string. + + +### TS Variables + +#### no-misused-new {#TSLINT_NMW} +Warns on apparent attempts to define constructors for interfaces or new for classes. + + +#### no-this-alias {#TSLINT_NTA} +This rule prohibits assigning variables to this. + + +#### no-unnecessary-type-arguments {#TSLINT_NUTA} +Type parameters in TypeScript may specify a default value. + + +#### no-unnecessary-type-assertion {#TSLINT_NUTAS} +This rule aims to prevent unnecessary type assertions. + + +#### no-unnecessary-type-constraint {#TSLINT_NUTC} +Disallows unnecessary constraints on generic types. + + +#### no-unused-vars {#TSLINT_NUV} +This rule extends the base eslint/no-unused-vars rule. It adds support for TypeScript features, such as types. + + ### Variables #### no-delete-var {#ESLINT_NDV} @@ -274,7 +467,3 @@ The purpose of the delete operator is to remove a property from an object. Using This rule can help you locate potential ReferenceErrors resulting from misspellings of variable and parameter names, or accidental implicit globals (for example, from forgetting the var keyword in a for loop initializer). -#### no-unused-vars {#ESLINT_NUV} -Variables that are declared and not used anywhere in the code are most likely an error due to incomplete refactoring. Such variables take up space in the code and can lead to confusion by readers. - - diff --git a/OpenStaticAnalyzer/javascript/doc/usersguide/md/Main.md b/OpenStaticAnalyzer/javascript/doc/usersguide/md/Main.md index d155bf8..49ece8d 100644 --- a/OpenStaticAnalyzer/javascript/doc/usersguide/md/Main.md +++ b/OpenStaticAnalyzer/javascript/doc/usersguide/md/Main.md @@ -26,6 +26,8 @@ The most important product characteristics of OpenStaticAnalyzer are the followi - [ESLint] coding rule violations + - [TypeScript-ESLint] coding rule violations in TypeScript (Experimental) + - [SONARQUBE™] platform 8.0 (“SonarQube” in the following) coding rule violations - Clone detection (copy-pasted source code fragments) extended with clone tracking and "clone smells" @@ -41,6 +43,7 @@ The most important product characteristics of OpenStaticAnalyzer are the followi - Coding rule violation metrics [ESLint]:http://eslint.org/ +[TypeScript-ESLint]:https://typescript-eslint.io/ [SONARQUBE™]:https://www.sonarqube.org By continuous static analysis, the software developers can: @@ -51,7 +54,7 @@ By continuous static analysis, the software developers can: - the number of errors in delivered software can be reduced, so the operational risks can be decreased, increasing the company's reputation. -OpenStaticAnalyzer can analyze source code conforming to ECMAScript 2015 (ECMAScript 6). +OpenStaticAnalyzer can analyze source code conforming to ECMAScript 2022. With the help of the filtering mechanism it is possible to specify a certain part of the ASG to be used (or not to be used) during the analysis, hence the results can be made more focused and the usage of memory and CPU can be reduced (e.g. generated source files or test code can be filtered out). @@ -77,7 +80,7 @@ OpenStaticAnalyzer supports the following x86 and x86-64 platforms: ## Requirements {#requirements-section} -In order to use OpenStaticAnalyzer for JavaScript, it is necessary to have Node.js 8.x.x installed on the computer and the necessary environment variable (PATH) must be set correctly. +In order to use OpenStaticAnalyzer for JavaScript, it is necessary to have Node.js 12.x.x installed on the computer and the necessary environment variable (PATH) must be set correctly. In case of Windows, the Microsoft Visual C++ 2017 Redistributable Package must be installed. It can be downloaded from the following URL: @@ -98,7 +101,7 @@ set "PATH=C:\Program Files\nodejs\;%PATH%" E.g.: for the Linux package: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.bash} -export "PATH=/opt/node-v8.11.2-linux-x64/bin:$PATH" +export "PATH=/opt/node-v10.24.1-linux-x64/bin:$PATH" export "GCONV_PATH=/usr/lib/x86_64-linux-gnu/gconv" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -161,11 +164,11 @@ OpenStaticAnalyzer can be executed with the following parameters: # Finally, test1742_b.js is not needed: -test1742_b.js - + **-nodeOptions** - + : Extra parameters can be added for the NodeJS used by OpenStaticAnalyzer. For instance the maximum heap memory of the v8 (used by Node) can be set manually if the default value is not enough. - + **-runMetricHunter** : This parameter turns on or off the MetricHunter module. With this feature, OpenStaticAnalyzer lists metric threshold violations. Its value can be "true" (turn this feature on) or "false" (turn this feature off). The default value is "true". @@ -199,7 +202,7 @@ OpenStaticAnalyzer can be executed with the following parameters: : The name of the directory with date inside the result directory of the project. If it is not set, then the current date is used. **-cleanResults** - + : Cleans all but the last n number of timestamped result directory of the current project. **-cleanProject** @@ -217,11 +220,11 @@ OpenStaticAnalyzer can be executed with the following parameters: **-runDCF** : This parameter turns on or off the DuplicatedCodeFinder module. With this feature, OpenStaticAnalyzer identifies copy-pasted code fragments. Its value can be "true" (turn this feature on) or "false" (turn this feature off). The default value is "true". - + **-runMET** : This parameter turns on or off the Metric module. With this feature, OpenStaticAnalyzer computes source code metrics. Its value can be "true" (turn this feature on) or "false" (turn this feature off). The default value is "true". - + **-profileXML** : Global configuration file for OpenStaticAnalyzer. Its *tool-options* tag can be used to override the default metric thresholds for the MetricHunter tool or define custom metric formulas for the UserDefinedMetrics tool. Furthermore, its *rule-options* tag can enable/disable or modify the priorities of multiple rules. An example profile xml file is shown below: @@ -286,7 +289,7 @@ OpenStaticAnalyzer can be executed with the following parameters: **-pattern** : The pattern file or pattern directory for LIM2Patterns. By default it searches for the predefined Anti Patterns found in Tools/Patterns/AntiPatterns. - + # Usage Execute the following command to analyze the source code of a software system: @@ -432,6 +435,7 @@ Known bugs and deficiencies of OpenStaticAnalyzer for JavaScript. - OpenStaticAnalyzer places the results into the directory specified by the projectName parameter. If special characters (like '\<', '\>', etc.) are used in the parameter, the analysis will probably fail. - Variable usage edges are in experimental version. There are cases which are not handled perfectly. +- The experimental typescript parser currently used for detecting coding rule violations will return errors when it's trying to lint files in typescript projects which aren't part of the analyzed project (not included in either "include" or "exclude" fields in tsconfig.json). This will usually not halt the linting process, but might produce inaccurate results. # FAQ diff --git a/OpenStaticAnalyzer/javascript/doc/usersguide/md/SourceCodeMetricsRef.md b/OpenStaticAnalyzer/javascript/doc/usersguide/md/SourceCodeMetricsRef.md index 0983391..879beef 100644 --- a/OpenStaticAnalyzer/javascript/doc/usersguide/md/SourceCodeMetricsRef.md +++ b/OpenStaticAnalyzer/javascript/doc/usersguide/md/SourceCodeMetricsRef.md @@ -17,17 +17,13 @@ The following table summarizes the metrics, their abbreviations and their corres Category Metric name Abbreviation Class Component File Function Method ---------------------- ------------------------------- ------------- ------- ----------- ------ ---------- -------- Complexity metrics McCabe's Cyclomatic Complexity McCC X X X - Nesting Level NL X X X - Nesting Level Else-If NLE X X X Weighted Methods per Class WMC X Documentation metrics API Documentation AD X - Comment Density CD X X X Comment Lines of Code CLOC X X X X Documentation Lines of Code DLOC X X X Public Documented API PDA X Public Undocumented API PUA X Total API Documentation TAD X - Total Comment Density TCD X X X X Total Comment Lines of Code TCLOC X X X X Total Public Documented API TPDA X Total Public Undocumented API TPUA X @@ -67,19 +63,6 @@ The following table summarizes the metrics, their abbreviations and their corres **File:** complexity of the file expressed as the number of independent control flow paths in it. It is calculated as the sum of the McCabe’s Cyclomatic Complexity values of the methods can be found in the file. -#### Nesting Level (NL) {#NL} - -**Method, Function:** complexity of the method/function expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes. The following instructions are taken into account: if, else-if, else, for, for-in, for-of, while, do-while, switch, try, catch, finally and block statements that are directly inside another block statement. The following instructions do not increase the value by themselves; however, if additional embeddedness can be found in their blocks, they are considered: case and default label (which belong to a switch instruction). - -**Class:** complexity of the class expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes. It is calculated as the maximum nesting level (NL) of its local methods. - - -#### Nesting Level Else-If (NLE) {#NLE} -**Method, Function:** complexity of the method/function expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes, where in the if-else-if construct only the first if instruction is considered. The following instructions are taken into account: if, for, while, conditional expression. The following instructions do not increase the value by themselves; however, if additional embeddedness can be found in their blocks, they are considered: else, else if (i.e. in the if-else-if construct the use of else-if does not increase the value of the metric), try, except, finally. - -**Class:** complexity of the class expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes, where in the if-else-if construct only the first if instruction is considered. It is calculated as the maximum nesting level (NLE) of its local methods. - - #### Weighted Methods per Class (WMC) {#WMC} **Class:** complexity of the class expressed as the number of independent control flow paths in it. It is calculated as the sum of the McCabe’s Cyclomatic Complexity (McCC) values of its local methods. @@ -90,12 +73,6 @@ The following table summarizes the metrics, their abbreviations and their corres #### API Documentation (AD) {#AD} **Class:** ratio of the number of documented methods in the class +1 if the class itself is documented to the number of all methods in the class + 1 (the class itself). -#### Comment Density (CD) {#CD} -**Method, Function:** ratio of the comment lines of the method/function (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC). - -**Class:** ratio of the comment lines of the class (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC). - - #### Comment Lines of Code (CLOC) {#CLOC} **Method, Function:** number of comment and documentation code lines of the method/function; however, its anonymous and local classes are not included. @@ -125,15 +102,6 @@ The following table summarizes the metrics, their abbreviations and their corres **Component:** ratio of the number of documented classes and methods in the component to the number of all of its classes and methods, including its subcomponents. -#### Total Comment Density (TCD) {#TCD} - -**Method/Function:** ratio of the total comment lines of the method/function (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). - -**Class:** ratio of the total comment lines of the class (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). - -**Component:** ratio of the total comment lines of the component (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). - - #### Total Comment Lines of Code (TCLOC) {#TCLOC} **Method/Function:** number of comment and documentation code lines of the method/function, including its local classes. diff --git a/OpenStaticAnalyzer/python/CMakeLists.txt b/OpenStaticAnalyzer/python/CMakeLists.txt index ba09a45..ca6e3bc 100644 --- a/OpenStaticAnalyzer/python/CMakeLists.txt +++ b/OpenStaticAnalyzer/python/CMakeLists.txt @@ -44,9 +44,9 @@ add_custom_generated_copy_dependency_to_tools_dir (Pylint_2.rul Pylint2Graph) add_custom_generated_copy_dependency_to_tools_dir (Pylint.conf Pylint2Graph) add_custom_generated_copy_dependency_to_tools_dir (UserDefinedMetrics${EXE}) add_custom_generated_copy_dependency_to_tools_dir (Sonar2Graph${EXE}) -add_custom_generated_copy_dependency_to_tools_dir (LIM2Patterns_python${EXE} LIM2Patterns_python LIM2Patterns${EXE}) -add_custom_generated_copy_dependency_to_tools_dir (Patterns LIM2Patterns_python Patterns DIRECTORY) -add_custom_generated_copy_dependency_to_tools_dir (Lib LIM2Patterns_python Lib DIRECTORY) +add_custom_generated_copy_dependency_to_tools_dir (LIM2Patterns${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (Patterns LIM2Patterns Patterns DIRECTORY) +add_custom_generated_copy_dependency_to_tools_dir (Lib LIM2Patterns Lib DIRECTORY) add_custom_generated_copy_dependency( ${OSA_TARGET_NAME} diff --git a/OpenStaticAnalyzer/python/doc/usersguide/md/Main.md b/OpenStaticAnalyzer/python/doc/usersguide/md/Main.md index ca1680f..8e24058 100644 --- a/OpenStaticAnalyzer/python/doc/usersguide/md/Main.md +++ b/OpenStaticAnalyzer/python/doc/usersguide/md/Main.md @@ -228,7 +228,7 @@ Filtered files will not appear in the results. The filter file is a simple text : The name of the directory with date inside the result directory of the project. If it is not set, then the current date is used. **-cleanResults** - + : Cleans all but the last n number of timestamped result directory of the current project. **-projectBaseDir** diff --git a/OpenStaticAnalyzer/python/doc/usersguide/md/SourceCodeMetricsRef.md b/OpenStaticAnalyzer/python/doc/usersguide/md/SourceCodeMetricsRef.md index 3be4d4a..9259b3b 100644 --- a/OpenStaticAnalyzer/python/doc/usersguide/md/SourceCodeMetricsRef.md +++ b/OpenStaticAnalyzer/python/doc/usersguide/md/SourceCodeMetricsRef.md @@ -24,18 +24,12 @@ The following table summarizes the metrics, their abbreviations and their corres ---------------------- ---------------------------------------- -------- ------------------ ------- -------- --------- ------ ------- Cohesion metrics Lack of Cohesion in Methods 5 LCOM5 X Complexity metrics McCabe's Cyclomatic Complexity McCC X X - Nesting Level NL X X - Nesting Level Else-If NLE X X Weighted Methods per Class WMC X Coupling metrics Coupling Between Object classes CBO X - Coupling Between Object classes Inverse CBOI X - Number of Incoming Invocations NII X X Number of Outgoing Invocations NOI X X Response set For Class RFC X - Documentation metrics Comment Density CD X X X X - Comment Lines of Code CLOC X X X X X + Documentation metrics Comment Lines of Code CLOC X X X X X Documentation Lines of Code DLOC X X - Total Comment Density TCD X X X X X Total Comment Lines of Code TCLOC X X X X X Inheritance metrics Depth of Inheritance Tree DIT X Number of Ancestors NOA X @@ -44,9 +38,7 @@ The following table summarizes the metrics, their abbreviations and their corres Number of Parents NOP X Size metrics Lines of Code LOC X X X X X Logical Lines of Code LLOC X X X X X - Number of Attributes NA X X X Number of Classes NCL X X - Number of Local Attributes NLA X Number of Local Methods NLM X Number of Methods NM X X X Number of Packages NPKG X @@ -54,11 +46,9 @@ The following table summarizes the metrics, their abbreviations and their corres Number of Statements NOS X X X Total Lines of Code TLOC X X X X X Total Logical Lines of Code TLLOC X X X X X - Total Number of Attributes TNA X X X X Total Number of Classes TNCL X X X Total Number of Directories TNDI X X Total Number of Files TNFI X X - Total Number of Local Attributes TNLA X Total Number of Local Methods TNLM X Total Number of Methods TNM X X X X Total Number of Packages TNPKG X X @@ -78,18 +68,6 @@ The following table summarizes the metrics, their abbreviations and their corres **File:** complexity of the file expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, for, while, except and conditional expression. Moreover, logical “and” and logical “or” expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, try, finally. -#### Nesting Level (NL) {#NL} - -**Method / Function:** complexity of the method/function expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes. The following instructions are taken into account: if, else-if, else, for, while, with, try, except, finally. - -**Class:** complexity of the class expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes. It is calculated as the maximum nesting level (NL) of its local methods. - -#### Nesting Level Else-If (NLE) {#NLE} - -**Method / Function:** complexity of the method/function expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes, where in the if-else-if construct only the first if instruction is considered. The following instructions are taken into account: if, else, for, while, with, try, except, finally. The following instructions do not increase the value by themselves; however, if additional embeddedness can be found in their blocks, they are considered: else-if (i.e. in the if-else-if construct the use of else-if does not increase the value of the metric). - -**Class:** complexity of the class expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes, where in the if-else-if construct only the first if instruction is considered. It is calculated as the maximum nesting level (NLE) of its local methods. - #### Weighted Methods per Class (WMC) {#WMC} **Class:** complexity of the class expressed as the number of independent control flow paths in it. It is calculated as the sum of the McCabe's Cyclomatic Complexity (McCC) values of its local methods. @@ -100,16 +78,6 @@ The following table summarizes the metrics, their abbreviations and their corres **Class:** number of directly used other classes (e.g. by inheritance, function call, type reference, attribute reference). Classes using many other classes highly depend on their environment, so it is difficult to test or reuse them; furthermore, they are very sensitive to the changes in the system. -#### Coupling Between Object classes Inverse (CBOI) {#CBOI} - -**Class:** number of other classes, which directly use the class. Classes which are used by many other classes have a high impact on the behavior of the system, and should be modified very carefully and tested intensively. - -#### Number of Incoming Invocations (NII) {#NII} - -**Method / Function:** number of other methods/functions and attribute initializations which directly call the method/function. If the method/function is invoked several times from the same method/function or attribute initialization, it is counted only once. - -**Class:** number of other methods and attribute initializations which directly call the local methods of the class. If a method is invoked several times from the same method or attribute initialization, it is counted only once. - #### Number of Outgoing Invocations (NOI) {#NOI} **Method / Function:** number of directly called methods/functions. If a method/function is invoked several times, it is counted only once. @@ -122,14 +90,6 @@ The following table summarizes the metrics, their abbreviations and their corres ### Documentation metrics -#### Comment Density (CD) {#CD} - -**Method/Function:** ratio of the comment lines of the method/function (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC). - -**Class:** ratio of the comment lines of the class (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC). - -**Module:** ratio of the comment lines of the module (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC). - #### Comment Lines of Code (CLOC) {#CLOC} **Method/Function:** number of comment and documentation code lines of the method/function; however, its local classes are not included. @@ -148,18 +108,6 @@ The following table summarizes the metrics, their abbreviations and their corres **Module:** number of documentation code lines of the modul. -#### Total Comment Density (TCD) {#TCD} - -**Method/Function:** ratio of the total comment lines of the method/function (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). - -**Class:** ratio of the total comment lines of the class (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). - -**Module:** ratio of the total comment lines of the module (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). - -**Package:** ratio of the total comment lines of the package (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). - -**Component:** ratio of the total comment lines of the component (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). - #### Total Comment Lines of Code (TCLOC) {#TCLOC} **Method/Function:** number of comment and documentation code lines of the method/function, including its local classes. @@ -220,24 +168,12 @@ The following table summarizes the metrics, their abbreviations and their corres **File:** number of non-empty and non-comment code lines in the file. -#### Number of Attributes (NA) {#NA} - -**Class:** number of attributes in the class, including the inherited ones; however, the attributes of its nested and local classes are not included. - -**Module:** number of attributes in the module. - -**Package:** number of attributes in the package; however, attributes of its subpackages are not included. - #### Number of Classes (NCL) {#NCL} **Module:** number of classes in the module. **Package:** number of classes in the package; however, the classes of its subpackages are not included. -#### Number of Local Attributes (NLA) {#NLA} - -**Class:** number of local (i.e. not inherited) attributes in the class; however, the attributes of nested and local classes are not included. - #### Number of Local Methods (NLM) {#NLM} **Class:** number of local (i.e. not inherited) methods in the class; however, the methods of nested and local classes are not included. @@ -290,16 +226,6 @@ The following table summarizes the metrics, their abbreviations and their corres **Component:** number of non-empty and non-comment code lines of the component, including its subcomponents. -#### Total Number of Attributes (TNA) {#TNA} - -**Class:** number of attributes in the class, including the inherited ones, as well as the inherited and local attributes of its nested and local classes. - -**Module:** number of attributes in the module. - -**Package:** number of attributes in the package, including the attributes of its subpackages. - -**Component:** number of attributes in the component, including the attributes of its subcomponents. - #### Total Number of Classes (TNCL) {#TNCL} **Module:** number of classes in the module. @@ -320,10 +246,6 @@ The following table summarizes the metrics, their abbreviations and their corres **Component:** number of files that belong to the component, including its subcomponents. -#### Total Number of Local Attributes (TNLA) {#TNLA} - -**Class:** number of local (i.e. not inherited) attributes in the class, including the attributes of its nested and local classes. - #### Total Number of Local Methods (TNLM) {#TNLM} **Class:** number of local (i.e. not inherited) methods in the class, including the local methods of its nested and local classes. diff --git a/README.md b/README.md index 7ea342c..d2396ce 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![](OpenStaticAnalyzer/doc/logo/OSA_small.png) # OpenStaticAnalyzer™ -Copyright (c) 2004-2021 Department of Software Engineering, University of Szeged, Hungary. +Copyright (c) 2004-2022 Department of Software Engineering, University of Szeged, Hungary. ## About @@ -18,6 +18,8 @@ The most important product characteristics of OpenStaticAnalyzer are the followi - Powerful filter management - Coding issue detection: - Metric threshold violations (MetricHunter module) + - Common programming mistakes (clang-tidy) + - [Cppcheck] 2.5 coding rule violation - Re-prioritized and carefully selected [PMD] 6.32.0 coding rule violations - [SpotBugs] 4.2.2 coding rule violations - [Pylint] 1.9.4 and 2.3.1 coding rule violations @@ -31,8 +33,9 @@ The most important product characteristics of OpenStaticAnalyzer are the followi - Source code metrics - Clone metrics - Coding rule violation metrics -- Supported languages: Java, Python, C#, JavaScript (C/C++ will be available in the near future). +- Supported languages: Java, Python, C#, JavaScript, C/C++. +[Cppcheck]:http://cppcheck.sourceforge.net/ [PMD]:https://pmd.github.io [SpotBugs]:https://spotbugs.github.io [Pylint]:http://www.pylint.org/ @@ -45,7 +48,7 @@ By continuous static analysis, the software developers can: - the number of errors in delivered software can be reduced, so the operational risks can be decreased, increasing the company's reputation. ## License -OpenStaticAnalyzer 4.1 is licensed under the [European Union Public Licence](https://joinup.ec.europa.eu/software/page/eupl) (EUPL) v1.2. +OpenStaticAnalyzer 5.0 is licensed under the [European Union Public Licence](https://joinup.ec.europa.eu/software/page/eupl) (EUPL) v1.2. OpenStaticAnalyzer is free software, distributed in the hope that it will be useful, but on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the LICENSE file for more details. @@ -61,22 +64,25 @@ OpenStaticAnalyzer is free software, distributed in the hope that it will be use [JavaScript](OpenStaticAnalyzer/javascript/doc/usersguide/md/Main.md) +[C/C++](OpenStaticAnalyzer/cpp/doc/usersguide/md/Main.md) + ### How to compile In order to build the OpenStaticAnalyzer software package the following tools are required: -- CMake 3.16.0 +- CMake 3.19.0 - Compiler - Linux : gcc 10.2 - Windows : Microsoft Visual Studio 2017, NASM 2.14, Perl 5.30 - - Install Windows 8.1 SDK and Windows Universal CRT SDK in Visual Studio Installer (if Visual Studio is already installed, then run the installer, Modify > Invidvidual components > Install) + - Install Windows 8.1 SDK and Windows Universal CRT SDK in Visual Studio Installer (if Visual Studio is already installed, then run the installer, Modify > Individual components > Install) - JDK 11 - Gradle 5.3 - Ant 1.10 - Apache Maven 3.2.5 - Pandoc 1.16 -- Node 8.x.x +- Node 12.x.x +- Ninja (for building the clang on windows) Some of the 3rd party libraries are used as a submodule so either `--recursive` diff --git a/cl/CAN/CMakeLists.txt b/cl/CAN/CMakeLists.txt new file mode 100644 index 0000000..f1a9185 --- /dev/null +++ b/cl/CAN/CMakeLists.txt @@ -0,0 +1,10 @@ +set (PROGRAM_NAME CAN) + +set (SOURCES + src/main.cpp +) + +add_executable(${PROGRAM_NAME} ${SOURCES}) +add_dependencies(${PROGRAM_NAME} clang ${COLUMBUS_GLOBAL_DEPENDENCY}) +target_link_libraries(${PROGRAM_NAME} common z ${CLANG_COMMON_LIBRARIES} ${COMMON_EXTERNAL_LIBRARIES}) +set_visual_studio_project_folder(${PROGRAM_NAME} TRUE) diff --git a/cl/CAN/src/main.cpp b/cl/CAN/src/main.cpp new file mode 100644 index 0000000..2e5205f --- /dev/null +++ b/cl/CAN/src/main.cpp @@ -0,0 +1,302 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include +#include +#include +#include +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define PROGRAM_NAME "CAN" +#define EXECUTABLE_NAME PROGRAM_NAME + + +using namespace std; +using namespace llvm; +using namespace clang; +using namespace tooling; +using namespace common; + +namespace +{ +// Tool CL options. +cl::OptionCategory category(EXECUTABLE_NAME " options"); +cl::opt outputFilename("o", cl::desc("AST file to output"), cl::Required, cl::cat(category)); +cl::opt statFilename("stat", cl::desc("Statistics file"), cl::cat(category)); +cl::opt configFilename("config", cl::desc("Configuration file"), cl::cat(category)); +cl::opt changePathFrom("changepathfrom", cl::desc("Part of the paths needed to be replaced"), cl::cat(category)); +cl::opt changePathTo("changepathto", cl::desc("New value of the path to be inserted"), cl::cat(category)); +cl::opt filterPath("fltp", cl::desc("Path to the softfilter file"), cl::cat(category)); + +// Handles comments. +class CANAction : public ASTFrontendAction +{ +private: + class MyCommentHandler: public CommentHandler + { + public: + ofstream commentFile; + + private: + const FileEntry *prevFileEntry; + + bool HandleComment(Preprocessor& pp, SourceRange comment) override + { + const SourceManager& sm = pp.getSourceManager(); + const SourceLocation beg = comment.getBegin(); + const SourceLocation end = comment.getEnd(); + + const unsigned bl = sm.getSpellingLineNumber(beg); + const unsigned bc = sm.getSpellingColumnNumber(beg); + const unsigned el = sm.getSpellingLineNumber(end); + const unsigned ec = sm.getSpellingColumnNumber(end); + + if (const FileEntry *F = sm.getFileEntryForID(sm.getFileID(beg))) + { + if (prevFileEntry != F) + { + //new file encountered + prevFileEntry = F; + commentFile << (char)1 << ' '; //this marks that the line is for a file + + string filename = F->getName().str(); + + // We need to get the canonical (absolute) path for the file, as the CWD could change during build so relative paths make no sense + filename = common::pathCanonicalize(filename); + + // Unless, there is a "global" string replace on paths (which we sometimes use for relative paths, but these are all relative to one specific "folder") + if(filename.c_str() && changePathFrom.c_str() && changePathTo.c_str()) + filename = common::replace(filename.c_str(), changePathFrom.c_str(), changePathTo.c_str()); + + commentFile << std::quoted(filename) << '\n'; + } + + commentFile << (char)0 << ' '; //this marks that the line is for a comment + + const char* b = sm.getCharacterData(beg); + const char* e = sm.getCharacterData(end); + + commentFile << bl << ' ' << bc << ' ' << el << ' ' << ec << ' ' << quoted(string(b, e - b)) << '\n'; + } + + return false; + } + + }; + MyCommentHandler myHandler; + +public: + unique_ptr CreateASTConsumer(CompilerInstance &Compiler, StringRef InFile) override + { + // "Empty" class - we do nothing with the AST, but we must have this even if 'usePreprocessorOnly' is true. + class Consumer : public clang::ASTConsumer + { + void HandleTranslationUnit(clang::ASTContext &context) override {} + }; + + // Setup output file according to the tool options and the current TU filename. + // Binary mode is needed to avoid CR/LF confusion on Windows. + myHandler.commentFile = ofstream(outputFilename + ".comment", ofstream::binary); + return unique_ptr(new Consumer()); + } + + bool BeginSourceFileAction(CompilerInstance &ci) override + { + // Set comment handler. + Preprocessor& pp = ci.getPreprocessor(); + pp.addCommentHandler(&myHandler); + return true; + } + + void EndSourceFileAction() override + { + myHandler.commentFile.close(); + } + +}; + +enum class Language +{ + c, + cpp, + objc +}; + +vector loadSystemIncludeConfiguration(Language language, const string& filename) +{ + vector includeDirs; + constexpr int MAX_BUFFER_SIZE = 8192; + char buffer[MAX_BUFFER_SIZE]; + + if (language == Language::cpp) + getPrivateProfileSection("IncludePath_cpp", buffer, MAX_BUFFER_SIZE, filename.c_str()); + else if (language == Language::c) + getPrivateProfileSection("IncludePath_c", buffer, MAX_BUFFER_SIZE, filename.c_str()); + else + return includeDirs; + + list keyValueList; + convertZeroTerminatedStringList(buffer, keyValueList); + + for (const auto& kv : keyValueList) + { + auto equalSignPos = kv.find_first_of('='); + if (equalSignPos != string::npos) + { + string directoryName; + pathCanonicalize(directoryName, kv.substr(equalSignPos + 1)); + includeDirs.push_back(directoryName); + } + } + return includeDirs; +} + +int run(int argc, const char** argv) +{ + WriteMsg::setAutomaticFlush(true); + + // Parse options with the common parser. + CommonOptionsParser parser(argc, argv, category); + const std::vector& files = parser.getSourcePathList(); + + if (files.size() != 1) + throw std::runtime_error("program requires exactly one input file"); + + for (const auto& x : parser.getCompilations().getCompileCommands(files.front())) + { + for (auto y : x.CommandLine) + WriteMsg::write(WriteMsg::mlNormal, "%s ", y.c_str()); + + WriteMsg::write(WriteMsg::mlNormal, "\n"); + } + + auto sysIncludes = loadSystemIncludeConfiguration(Language::cpp, configFilename); + + CommandLineArguments cla; + + for (const auto& sysInclude: sysIncludes) + { + cla.push_back("-Xclang"); + cla.push_back("-internal-isystem" + sysInclude); + } + + // Create Clang tool. + ClangTool tool(parser.getCompilations(), files); + + //this may not work + if (!cla.empty()){ + tool.clearArgumentsAdjusters(); //this may not be needed + tool.appendArgumentsAdjuster(tooling::getInsertArgumentAdjuster(cla, tooling::ArgumentInsertPosition::BEGIN)); + } + + class MyTextDiagnosticPrinter : public TextDiagnosticPrinter + { + public: + MyTextDiagnosticPrinter(raw_ostream &os, DiagnosticOptions *diags) : TextDiagnosticPrinter(os, diags) {} + void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) override + { + DirectoryFilter directoryFilter; + directoryFilter.openFilterFile(filterPath); + string canonicalFileName = common::pathCanonicalize(Info.getSourceManager().getFilename(Info.getLocation()).str()); + + // If the error is not in a filtered file. + if (!directoryFilter.isFilteredOut(canonicalFileName)) + TextDiagnosticPrinter::HandleDiagnostic(DiagLevel, Info); + } + }; + + // ToolAction to create binary AST and comment files. + class : public FrontendActionFactory + { + public: + // This variable is incremented during each invocation and effectively works as an index into the input file array. + int myHack = 0; + //unordered_map> commentsForFile; + + // Stores the input file names. + const vector* pMyInputs; + + bool runInvocation(shared_ptr inv, FileManager* files, shared_ptr pch, DiagnosticConsumer* dgc) override + { + auto opts = &inv->getDiagnosticOpts(); + auto dc = CompilerInstance::createDiagnostics(opts, dgc, false); + + MyTextDiagnosticPrinter consumer(llvm::errs(), opts); + dc->setClient(&consumer); + + auto ast = ASTUnit::LoadFromCompilerInvocationAction(std::move(inv), std::move(pch), dc, create().get()); + if (ast == nullptr) + return false; + + if (ast->Save(outputFilename)) + return false; + + if (dc->hasErrorOccurred() || + dc->hasUncompilableErrorOccurred() || + dc->hasFatalErrorOccurred() || + dc->hasUnrecoverableErrorOccurred()) + { + return false; + } + + return true; + } + + unique_ptr create() override { return unique_ptr(new CANAction()); } + } factory; + factory.pMyInputs = &files; + + // Run the tool. + int ret = tool.run(&factory); + + return ret; +} + +} // anonymous namespace + +int main(int argc, const char** argv) +{ + try + { + int ret = run(argc, argv); + common::writeMinimalStatFile(statFilename); + return ret; + } + catch (const exception& ex) + { + cerr << "Error: " << ex.what() << endl; + } + catch (...) + { + cerr << "Error: unknown exception." << endl; + } + return EXIT_FAILURE; +} diff --git a/cl/CAN2Lim/CMakeLists.txt b/cl/CAN2Lim/CMakeLists.txt new file mode 100644 index 0000000..feb13b1 --- /dev/null +++ b/cl/CAN2Lim/CMakeLists.txt @@ -0,0 +1,23 @@ +set (PROGRAM_NAME CAN2Lim) + +set (SOURCES + src/ASTConversionInfo.cpp + inc/ASTConversionInfo.h + src/ASTVisitor.cpp + inc/ASTVisitor.h + src/main.cpp + src/MergeUID.cpp + inc/MergeUID.h + inc/messages.h + src/CommentProcessor.cpp + inc/CommentProcessor.h + src/Linker.cpp + inc/Linker.h + src/clangHelpers.cpp + inc/clangHelpers.h +) + +add_executable(${PROGRAM_NAME} ${SOURCES}) +add_dependencies(${PROGRAM_NAME} clang ${COLUMBUS_GLOBAL_DEPENDENCY}) +target_link_libraries(${PROGRAM_NAME} clangsupport lim threadpool strtable common csi io ${CLANG_COMMON_LIBRARIES} ${COMMON_EXTERNAL_LIBRARIES}) +set_visual_studio_project_folder(${PROGRAM_NAME} TRUE) diff --git a/cl/CAN2Lim/inc/ASTConversionInfo.h b/cl/CAN2Lim/inc/ASTConversionInfo.h new file mode 100644 index 0000000..a91eb37 --- /dev/null +++ b/cl/CAN2Lim/inc/ASTConversionInfo.h @@ -0,0 +1,222 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _CAN2LIM_AST_CONVERSION_INFO_H +#define _CAN2LIM_AST_CONVERSION_INFO_H + +#include "MergeUID.h" +#include "CommentProcessor.h" +#include + +#include +#include +#include +#include +#include +#include "Linker.h" +#include +#include +#include +#include +#include +#include +#include + +class GlobalASTConversionInfo +{ +private: + // Helper for UID hashing. + struct UIDHasher + { + typedef std::shared_ptr argument_type; + typedef size_t result_type; + + result_type operator()(const argument_type& o) const + { + if (!o) + return 0; + + return o->hash(); + } + }; + + // Helper for UID equivalence. + struct UIDEq + { + typedef std::shared_ptr first_argument_type; + typedef std::shared_ptr second_argument_type; + typedef bool result_type; + + result_type operator()(const first_argument_type& lhs, const second_argument_type& rhs) const + { + if (!lhs || !rhs) + return lhs.get() == rhs.get(); + + return lhs->equals(*rhs); + } + }; + + // Helper for UID equivalence. + struct NoPosUIDEq + { + typedef std::shared_ptr first_argument_type; + typedef std::shared_ptr second_argument_type; + typedef bool result_type; + + result_type operator()(const first_argument_type& lhs, const second_argument_type& rhs) const + { + if (!lhs || !rhs) + return lhs.get() == rhs.get(); + + return lhs->noPositionEquals(*rhs); + } + }; + +public: + GlobalASTConversionInfo(columbus::lim::asg::Factory& limFactory, const clang::metrics::Output& output, columbus::LimOrigin& origin); + + columbus::lim::asg::Factory& limFactory; + const clang::metrics::Output& metricsOutput; + + columbus::LimOrigin& limOrigin; + + // Filter the folders based on the filter-file + void filterFolders(); + + // Matches UIDs to LIM nodes. + std::unordered_map, columbus::lim::asg::base::Base*, UIDHasher, UIDEq> limTable; + + // Matches UIDs to LIM Types. + std::unordered_map, columbus::lim::asg::type::Type*, UIDHasher, UIDEq> typeTable; + + std::unordered_set, UIDHasher, UIDEq> incompleteNodes; + + CommentProcessor commentProcessor; + + // Called after all ASTs have been converted. + void finalizeConversion(); + + void addMemberToScopeList(columbus::lim::asg::SourcePosition& position, columbus::lim::asg::logical::Member* member, columbus::lim::asg::physical::File* file); + + void addGlobalNamespaceToScopeList(std::vector& scopeList); + + // Stores scope beginning and endings for positioned elements (used for comment processing) + // TODO: Duplicate + struct FileComparator + { + bool operator()(const columbus::lim::asg::physical::File* lhs, const columbus::lim::asg::physical::File* rhs) const + { + return lhs->getId() < rhs->getId(); + } + }; + std::map, FileComparator> scopeListPerFile; + + //We have to store namespaces and only add their metrics at the end (since for example the LOC of a namespace may grow during the processing of different TUs) + std::vector>> namespaces; + + // Linker singleton + Linker& linker; + + // A map for the files that we have created in the LIM. + // They key is the filename, in the format of clang FileEntry->getName() + // The value is a pointer to the LIM file node + //std::unordered_map fileLibrary; + + std::string changePathFrom; + std::string changePathTo; + + std::map correctedFileNameToFileNode; + std::map canonicalFileNameToFileNode; + + //TODO: refactor this later + std::map filesAlreadyProcessed; + + std::map> fileNode_to_TUNodes; + + struct ASTIdentifier + { + std::string fileName; + uintmax_t fileSize; + ASTIdentifier() {} + ASTIdentifier(const std::string& fullPath) + : fileName(common::pathFindFileName(fullPath)), + fileSize(boost::filesystem::file_size(fullPath)) + {} + + bool operator<(const ASTIdentifier& rhs) const + { + return std::tie(this->fileSize, this->fileName) < std::tie(rhs.fileSize, rhs.fileName); + } + bool operator==(const ASTIdentifier& rhs) const + { + return std::tie(this->fileSize, this->fileName) == std::tie(rhs.fileSize, rhs.fileName); + } + }; + + std::map> componentsOfTU; +}; + +class GlobalASTConversionInfo_ThreadSafe +{ + GlobalASTConversionInfo& globalASTConversionInfo; + boost::recursive_mutex globalASTConversionInfoMutex; + +public: + GlobalASTConversionInfo_ThreadSafe(GlobalASTConversionInfo& globalASTConversionInfo) : globalASTConversionInfo(globalASTConversionInfo) {} + template + auto call(Operation o) -> decltype(o(globalASTConversionInfo)) + { + boost::lock_guard lock(globalASTConversionInfoMutex); + return o(globalASTConversionInfo); + } +}; + +class ASTConversionInfo +{ +public: + ASTConversionInfo(const std::string ASTFilename, const std::string compilationUnitName, GlobalASTConversionInfo_ThreadSafe& globalInfo, MergeUIDFactory& uidFactory); + + // The name of the AST file. + const std::string ASTFilename; + + // The full path of the AST file. + const std::string compilationUnitName; + + // Pointer to the current AST file being processed. + columbus::lim::asg::physical::File* pCurrentASTFile = nullptr; + + std::unordered_map filesOfTU; + + // Uniquely identifies an AST file based on it's full path and file size + const GlobalASTConversionInfo::ASTIdentifier currentASTIdentifier; + + std::shared_ptr originMap; + + GlobalASTConversionInfo_ThreadSafe& globalInfo; + + // The Mangle context. + std::shared_ptr pMyMangleContext; + + MergeUIDFactory& uidFactory; +}; + +extern class CANFilePathRenamer cANFilePathRenamer; + +#endif \ No newline at end of file diff --git a/cl/CAN2Lim/inc/ASTVisitor.h b/cl/CAN2Lim/inc/ASTVisitor.h new file mode 100644 index 0000000..19e3094 --- /dev/null +++ b/cl/CAN2Lim/inc/ASTVisitor.h @@ -0,0 +1,270 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _CAN2LIM_AST_VISITOR_H +#define _CAN2LIM_AST_VISITOR_H + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + + +#include "ASTConversionInfo.h" + +class ASTConverterConsumer : public clang::ASTConsumer +{ + public: + ASTConverterConsumer(ASTConversionInfo& conversionInfo); + + virtual void HandleTranslationUnit(clang::ASTContext &context) override; + + private: + ASTConversionInfo& conversionInfo; +}; + +class ASTConverterVisitor : public clang::RecursiveASTVisitor +{ + public: + ASTConverterVisitor(clang::ASTContext &context, ASTConversionInfo& conversionInfo); + + bool TraverseDecl(clang::Decl * decl); + + bool VisitTranslationUnitDecl(const clang::TranslationUnitDecl* decl); + + bool VisitVarDecl(const clang::VarDecl* decl); + bool VisitFieldDecl(const clang::FieldDecl* decl); + bool VisitEnumConstantDecl(const clang::EnumConstantDecl* decl); + bool VisitNamespaceDecl(const clang::NamespaceDecl* decl); + bool VisitRecordDecl(const clang::RecordDecl * decl); + void RecordDeclHelper(const clang::RecordDecl * decl, columbus::lim::asg::logical::Class * limClass, std::shared_ptr uid); + void CXXRecordDeclHelper(const clang::CXXRecordDecl * decl, columbus::lim::asg::logical::Class* limClass, std::shared_ptr uid); + columbus::lim::asg::logical::Class* buildClassGenericSpec(const clang::ClassTemplateSpecializationDecl * decl, std::shared_ptr uid); + columbus::lim::asg::logical::Class* buildClassGeneric(const clang::ClassTemplateDecl * decl, std::shared_ptr uid); + columbus::lim::asg::logical::Class* buildClass(const clang::CXXRecordDecl * decl, std::shared_ptr uid); + bool VisitCXXRecordDecl(const clang::CXXRecordDecl* decl); + bool VisitEnumDecl(const clang::EnumDecl* decl); + bool VisitClassScopeFunctionSpecializationDecl(const clang::ClassScopeFunctionSpecializationDecl * decl); + void methodBuildCommon(const clang::FunctionDecl * decl, columbus::lim::asg::logical::Method * limMethod, std::shared_ptr uid, bool nodeCreated, std::set usedTypes, bool isLambda = false); + bool buildMethodGenericSpec(const clang::FunctionDecl * specFunc, const clang::FunctionTemplateDecl * templateDecl); + bool buildLambda(const clang::CXXRecordDecl * lambdaClass); + bool buildMethodGeneric(const clang::FunctionDecl * decl, const clang::FunctionTemplateDecl * templateDecl); + bool buildSimpleMethod(const clang::FunctionDecl * decl); + bool VisitFunctionDecl(const clang::FunctionDecl* decl); + bool VisitFriendDecl(const clang::FriendDecl* decl); + bool VisitTypedefNameDecl(const clang::TypedefNameDecl * decl); + bool VisitObjCInterfaceDecl(clang::ObjCInterfaceDecl* decl); + bool VisitObjCMethodDecl(const clang::ObjCMethodDecl* decl); + bool VisitObjCProtocolDecl(clang::ObjCProtocolDecl* decl); + bool VisitObjCCategoryDecl(const clang::ObjCCategoryDecl* decl); + bool VisitObjCPropertyDecl(const clang::ObjCPropertyDecl* decl); + + bool VisitExpr(const clang::Expr * expr); + bool VisitCallExpr(const clang::CallExpr* stmt); + bool VisitObjCMessageExpr(const clang::ObjCMessageExpr* stmt); + bool VisitCXXThrowExpr(const clang::CXXThrowExpr* stmt); + bool VisitObjCAtThrowStmt(const clang::ObjCAtThrowStmt* stmt); + bool VisitCXXConstructExpr(const clang::CXXConstructExpr* stmt); + bool VisitDeclRefExpr(const clang::DeclRefExpr* stmt); + bool VisitMemberExpr(const clang::MemberExpr* stmt); + + bool TraverseLambdaExpr(clang::LambdaExpr* stmt); + + bool ConvertType(const clang::Type* type); + + // Handles common code for both CallExpr and ObjCMessageExpr. + template + bool HandleFunctionCalling(const CallType* callee, const CallType* caller, const clang::Stmt* stmt); + std::string getImprint(const clang::Stmt * stmt); + private: + // Helper. + template static auto toVoid(const T* ptr) -> typename std::enable_if::value, void*>::type + { + return (void*)(static_cast(ptr)); + } + template static auto toVoid(const T* ptr) -> typename std::enable_if::value, void*>::type + { + return (void*)(static_cast(ptr)); + } + template static auto toVoid(const T* ptr) -> typename std::enable_if::value, void*>::type + { + return (void*)(static_cast(ptr)); + } + + bool buildMethod(const clang::FunctionDecl * decl); + + // Iterates class decls. + void iterateDecls(const clang::Decl* decl, columbus::lim::asg::Class* limClass); + + // Returns the file for the given SourceLocation. + //columbus::lim::asg::physical::File& getFile(clang::SourceLocation loc); + + template + T * getOrCreateIncompleteNode(const clang::Decl * decl); + columbus::lim::asg::logical::Method * getOrCreateIncompleteNode_Method(const clang::FunctionDecl * decl); + columbus::lim::asg::logical::Class * getOrCreateIncompleteNode_Class(const clang::CXXRecordDecl * decl); + columbus::lim::asg::logical::Scope * getOrCreateIncompleteNode_Scope(const clang::Decl * decl); + + // Creates a new LIM node. + template bool createNode(std::shared_ptr uid, U*& out, const clang::Decl* decl); + + /// Creates a file node in the LIM + /// The input filename MUST be in the format given by clangtool FileEntry->getName() + columbus::lim::asg::physical::File * createFileNode(const clang::FileEntry *fileEntry); + + /// Gets a pointer to a file node in the LIM if exists, otherwise returns nullptr + /// The input filename MUST be in the format given by clangtool FileEntry->getName() + columbus::lim::asg::physical::File * getFileNode(const clang::FileEntry *fileEntry); + +public: + /// Gets a filenode in the LIM or creates it, if it is not yet created + /// The input filename MUST be in the format given by clangtool FileEntry->getName() + columbus::lim::asg::physical::File* getOrCreateFileNode(const clang::FileEntry *fileEntry); + +private: + clang::FileID locToFileID(const clang::SourceLocation & loc); + + // Setup new GenericParameter based on the argument Decl. + columbus::lim::asg::GenericParameter* createGenericParameter(const clang::NamedDecl* param); + + // Adds a new friendship edge to the Class. Takes care of setting this edge up. + void addFriendshipEdge(columbus::lim::asg::Class* limParent, columbus::NodeId friendId, const std::string& friendName); + + void createLIMType(const clang::Type* type); + + const clang::Decl* getDeclFromStmt(const clang::Stmt& stmt); + const clang::DeclContext* getFunctionContextFromStmt(const clang::Stmt& stmt); + const clang::Decl* getParentFromContext(const clang::Decl* decl); + + void handleAttributeAccess(const clang::ValueDecl* decl, const clang::FunctionDecl* func); + + // Returns the source position (with realization level) for decl. + columbus::lim::asg::SourcePosition getSourcePosition(const clang::NamespaceDecl* decl); + columbus::lim::asg::SourcePosition getSourcePosition(const clang::CXXRecordDecl * decl); + columbus::lim::asg::SourcePosition getSourcePosition(const clang::FriendDecl * decl); + columbus::lim::asg::SourcePosition getSourcePosition(const clang::TagDecl* decl); + columbus::lim::asg::SourcePosition getSourcePosition(const clang::FunctionDecl* decl); + columbus::lim::asg::SourcePosition getSourcePosition(const clang::ObjCMethodDecl* decl); + columbus::lim::asg::SourcePosition getSourcePosition(const clang::FieldDecl* decl); + columbus::lim::asg::SourcePosition getSourcePosition(const clang::VarDecl* decl); + columbus::lim::asg::SourcePosition getSourcePosition(const clang::EnumConstantDecl* decl); + columbus::lim::asg::SourcePosition getSourcePosition(const clang::ObjCInterfaceDecl* decl); + columbus::lim::asg::SourcePosition getSourcePosition(const clang::ObjCCategoryDecl* decl); + columbus::lim::asg::SourcePosition getSourcePosition(const clang::ObjCProtocolDecl* decl); + + columbus::lim::asg::SourcePosition getSourcePositionHelper(const clang::Decl* decl); + columbus::lim::asg::SourcePosition getSourcePositionHelper(clang::SourceLocation start, clang::SourceLocation end); + + template + T getPrimaryTemplateVersionOfMemberDecl(T input); + template T* createNodeHelper(); + + void addMemberEdge(const clang::Decl* parent, columbus::lim::asg::logical::Member* to); + + void addUsesEdgeForStmt(columbus::lim::asg::logical::Member * to, const clang::Stmt * stmt, bool recursive = true); + void addUsesEdgeForType(columbus::lim::asg::logical::Member* to, const clang::Type* type); + + bool addInstantiatesEdge(const clang::FunctionDecl * f, const clang::Type * type); + + template + void addTemplateArgumentEdge(const clang::TemplateArgument& arg, T* limTo); + + template + void addPositionEdge(columbus::lim::asg::logical::Member* limNode, const T* decl) + { + clang::SourceLocation loc = decl->getLocation(); + if (loc.isValid()) + { + columbus::lim::asg::physical::File *file = getOrCreateFileNode(sm.getFileEntryForID(locToFileID(loc))); + if (!file) + { + common::WriteMsg::write( + common::WriteMsg::mlDebug, + "Posedge ERROR: fileIDHash(%d) filename(%s), ptrAddress(%d) does not exist, but it should", + locToFileID(loc).getHashValue(), + ((std::string)context.getSourceManager().getFilename(loc)).c_str(), + context.getSourceManager().getFileEntryForID(locToFileID(loc))->getUniqueID().getFile() + ); + } + else + { + columbus::lim::asg::SourcePosition position = getSourcePosition(decl); + limNode->addIsContainedIn(file, position); + + // We add a sourcePosition to a list for comment and documenation detection. + // If this is a macro expansion, we add the comment to the first declaration in the expansion. + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + if (loc.isMacroID() && !globalInfo.scopeListPerFile[file].empty()) + { + // All macroexpanded declaration have the same sourcelocation, so we check, if the last one added is the same as this one. + // If it is, we will not add any comments to it. + SourcePoint sp = globalInfo.scopeListPerFile[file].back().scope.begin; + if (position.getLine() != sp.line || position.getColumn() != sp.column) + { + globalInfo.addMemberToScopeList(position, limNode, file); + } + } + else + { + globalInfo.addMemberToScopeList(position, limNode, file); + } + }); + } + } + } + + columbus::ASTFilter myFilter; + + clang::ASTContext& context; + + ASTConversionInfo& conversionInfo; + + clang::SourceManager &sm; + + // The clang visitor may visit a single type multiple types, which we do not want. Hence visited types are added here, + // and only types not yet here are visited. + std::unordered_set myVisitedTypes; + + // Stores the ID of the current translation unit. + columbus::lim::asg::physical::File* pMyCurrentTU = nullptr; + // TODO Handle the LinkageSpecDecl + columbus::lim::asg::LanguageKind languageKind; +}; + +class Convert2LimAction : public clang::ASTFrontendAction +{ + public: + Convert2LimAction(ASTConversionInfo& conversionInfo); + virtual std::unique_ptr CreateASTConsumer(clang::CompilerInstance &Compiler, llvm::StringRef InFile); + + private: + ASTConversionInfo& conversionInfo; +}; + +std::unique_ptr newConvert2LimActionFactory(ASTConversionInfo& conversionInfo); + +#endif diff --git a/cl/CAN2Lim/inc/CommentProcessor.h b/cl/CAN2Lim/inc/CommentProcessor.h new file mode 100644 index 0000000..e9a20bb --- /dev/null +++ b/cl/CAN2Lim/inc/CommentProcessor.h @@ -0,0 +1,51 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _CAN2LIM_COMMENTPROCESSOR_H +#define _CAN2LIM_COMMENTPROCESSOR_H + +#include +#include +#include +#include + +class GlobalASTConversionInfo; + +class CommentProcessor { +public: + GlobalASTConversionInfo& conversionInfo; + + std::vector> docCache; + + // Stores comments ordered according to source position. + std::unordered_map> commentTablePerFile; + + void addDocumentationToMember(columbus::lim::asg::logical::Member * member, const CommentData & comment, bool postAdd); + void addCommentToMember(columbus::lim::asg::logical::Member * member, const CommentData & comment, const CommentData * prevComment); + +public: + CommentProcessor(GlobalASTConversionInfo & conversionInfo); + + void bindCommentsToLimTree(columbus::lim::asg::physical::File* file); + void loadCommentStructure(const std::string & astFile); + +}; + +#endif \ No newline at end of file diff --git a/cl/CAN2Lim/inc/Linker.h b/cl/CAN2Lim/inc/Linker.h new file mode 100644 index 0000000..00141c7 --- /dev/null +++ b/cl/CAN2Lim/inc/Linker.h @@ -0,0 +1,110 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _CAN2LIM_LINKER_H +#define _CAN2LIM_LINKER_H + +#include +#include +#include "MergeUID.h" + +class GlobalASTConversionInfo; + +/* This singleton class is responsible for linking. Linking in our case means just to apply Declares edges from + Declarations to Definitions in the LIM tree. + Linking in compilers usually happens per component. Here we link all components at once, at the end of the conversion. + + The workflow is: + 1, During the visitation of the source file(s) + a, add each unresolved declaration to unresolved_declarations + b, add each definition to the UID_to_definitions map + c, build a component_to_files map + 2, Based on the above, at the very end of the CAN2Lim conversion, connect the declarations to definitions by calling + link_unresolved_declarations() + + But there is one catch right now. It is possibly that the same declaration links to different definitions in different components. + The LIM schema currently doesn't support this kind of edges (only with variants, which we don't use in current CAN). + As a result, if such case happens, we simply link the declaration to only one of them. Which is kinda bad, because it makes + the LIM file dependent on which definition we find last, so it might create silly, sporadic errors in tests. + The upside is that with this simplification, we can link faster. The SIMPLIFIED_LINKING switch makes the algorithm faster but + incorrectly (as there is no correct solution anyways). + + TODO: Extend LIM schema or use variants and solve this issue in link_unresolved_declarations(). After that, delete SIMPLIFIED_LINKING. +*/ +class Linker { +public: + static const bool LINKER_DEBUG = false; + static const bool SIMPLIFIED_LINKING = true; + +public: + GlobalASTConversionInfo &conversionInfo; + + std::vector,columbus::lim::asg::Member*>> unresolved_declarations; + std::vector,columbus::lim::asg::base::Base*>> unresolved_calls; + std::vector,columbus::lim::asg::logical::Method*>> unresolved_attribute_accesses; + + std::unordered_multimap, columbus::lim::asg::Member*, MergeUID::UIDHasher, MergeUID::NoPosUIDEq> UID_to_definitions; + + struct FilePtrComparator { + bool operator()(const columbus::lim::asg::physical::File* lhs, const columbus::lim::asg::physical::File* rhs) const{ + return lhs->getId() < rhs->getId(); + } + }; + // The file set must not be unordered, as that would make the order of elements undefined, and that makes the tests fail sporadically (different node order...) + std::unordered_map> component_to_files; + + std::unordered_map> file_to_components; + + // If the decl is a definition this function adds it to UID_to_definitions + // If it is a declaration inside a cpp file and the clang-tool finds it, it links it immediately to it's definition + // If it is a declaration and the definition is not found, the declaration is added to unresolved_declarations + // Note: Declarations in .h files are never bound to definition in a TU. That's because a declaration in a .h file might be linked to + // multiple definitions based on the component. + //void handle_decl(const clang::Decl* decl, std::shared_ptr uid, columbus::lim::asg::Member* limNode); + + void add_definition(columbus::lim::asg::Member * limNode, std::shared_ptr uid); + void add_declaration(columbus::lim::asg::Member * limNode, std::shared_ptr uid); + + // MUST only be called at the end of the conversion, when unresolved_declarations, UID_to_definitions, component_to_files are filled up. + // Also, all the files must have their belongsTo edges set properly, otherwise this will not work correctly. + // Note: It's roughly O(n^2), with SIMPLIFIED_LINKING it's roughly O(n), but it can be done faster if needed to. + bool link_unresolved_declarations(); + + bool link_unresolved_calls(); + + bool link_unresolved_attribute_accesses(); + + static Linker& getInstance(GlobalASTConversionInfo &conversionInfo) + { + static Linker instance(conversionInfo); + return instance; + } + + void print_debug_overview(); + +public: + Linker(Linker const&) = delete; + void operator=(Linker const&) = delete; + +private: + Linker(GlobalASTConversionInfo& conversionInfo) : conversionInfo(conversionInfo) {} +}; + +#endif \ No newline at end of file diff --git a/cl/CAN2Lim/inc/MergeUID.h b/cl/CAN2Lim/inc/MergeUID.h new file mode 100644 index 0000000..73c0e4f --- /dev/null +++ b/cl/CAN2Lim/inc/MergeUID.h @@ -0,0 +1,139 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef __CAN2LIM_MERGE_UID_H__ +#define __CAN2LIM_MERGE_UID_H__ + +#include +#include + +#include +#include + +#include + +#include + + +namespace clang +{ + class CompilerInstance; +} + +class MergeUID : public clang::metrics::UID +{ +public: + MergeUID(const std::string& mangledName, std::string fileName, unsigned lineNumber, unsigned columnNumber, bool isNamespace); + + const std::string& getMangledName() const { return mangledName; } + + const std::string& getFilename() const { return fileName; } + + bool noPositionEquals(const MergeUID& o) const + { + return mangledName == o.mangledName; + //return (isNamespace ? true : fileName == o.fileName) && mangledName == o.mangledName; + } + +private: + bool equals(const UID& rhs) const override; + std::size_t hash() const override; + + std::string getName() const override + { + return mangledName; + } + +private: + const std::string mangledName; + mutable std::string fileName; + const unsigned lineNumber, columnNumber; + const size_t hashValue; + static boost::mutex m; + + const bool isNamespace; +public: + //helpers for hashing in maps, unordered_maps, etc... + // Helper for UID hashing. + struct UIDHasher + { + typedef std::shared_ptr argument_type; + typedef size_t result_type; + + result_type operator()(const argument_type& o) const + { + if (!o) + return 0; + + return o->hash(); + } + }; + + // Helper for UID equivalence. + struct UIDEq + { + typedef std::shared_ptr first_argument_type; + typedef std::shared_ptr second_argument_type; + typedef bool result_type; + + result_type operator()(const first_argument_type& lhs, const second_argument_type& rhs) const + { + if (!lhs || !rhs) + return lhs.get() == rhs.get(); + + return lhs->equals(*rhs); + } + }; + + // Helper for UID equivalence. + struct NoPosUIDEq + { + typedef std::shared_ptr first_argument_type; + typedef std::shared_ptr second_argument_type; + typedef bool result_type; + + result_type operator()(const first_argument_type& lhs, const second_argument_type& rhs) const + { + if (!lhs || !rhs) + return lhs.get() == rhs.get(); + + return lhs->noPositionEquals(*rhs); + } + }; +}; + +class MergeUIDFactory : public clang::metrics::UIDFactory +{ +public: + std::unique_ptr create(const clang::Decl* decl, std::shared_ptr mangleContext) override; + std::unique_ptr createTypeId(const clang::QualType type, std::shared_ptr mangleContext); + +private: + static void declContextName(clang::SourceManager& sm, llvm::raw_string_ostream& ss, const clang::DeclContext* parent); + + void mangleTypeName(const clang::Type* type, llvm::raw_string_ostream& ss, std::shared_ptr mangleContext); + +private: + std::string declToFileName(const clang::Decl* decl, clang::ASTContext& astContext); + std::atomic itsMissingIdCounter { 0 }; +}; + + +#endif diff --git a/cl/CAN2Lim/inc/clangHelpers.h b/cl/CAN2Lim/inc/clangHelpers.h new file mode 100644 index 0000000..e488758 --- /dev/null +++ b/cl/CAN2Lim/inc/clangHelpers.h @@ -0,0 +1,56 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _CAN2LIM_HELPERS_H +#define _CAN2LIM_HELPERS_H + +#include + +bool isDefinition(const clang::TagDecl *decl); +bool isDefinition(const clang::FunctionDecl *decl); +bool isDefinition(const clang::ObjCProtocolDecl *decl); +bool isDefinition(const clang::ObjCCategoryDecl *decl); +bool isDefinition(const clang::ObjCInterfaceDecl *decl); +bool isDefinition(const clang::ValueDecl *decl); +bool isDefinition(const clang::VarDecl *decl); +bool isDefinition(const clang::FieldDecl *decl); +bool isDefinition(const clang::ObjCMethodDecl *decl); +bool isDefinition(const clang::NamespaceDecl *decl); + +// Deduce the type of decl with dynamic casts and return the answer (only works for LIM types that have declaration-definition pairs) +bool isDefinition(const clang::Decl *decl); + +// Gets the definition for the declaration if it's present in the TU +const clang::Decl * getLocalDefinition(const clang::Decl * decl); + +/// Sometimes we would like to add an id to a container in the LIM but we don't want to add duplicates. +/// This functionality is not implemented in the LIM API so here is a helper to check for it. +/// Note : It's O(n) +template +bool contains(IT begin, IT end, NODEPTR node) +{ + for (auto it = begin; it != end; ++it) + { + if (it->getId() == node->getId()) + return true; + } + return false; +} +#endif \ No newline at end of file diff --git a/cl/CAN2Lim/inc/messages.h b/cl/CAN2Lim/inc/messages.h new file mode 100644 index 0000000..9f9d707 --- /dev/null +++ b/cl/CAN2Lim/inc/messages.h @@ -0,0 +1,97 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _CAN2LIM_MESSAGES_H_ +#define _CAN2LIM_MESSAGES_H_ + +//main.cpp messages +#define CMSG_CAN2LIM_CONVERSION_START WriteMsg::mlNormal, "Conversion start...\n" +#define CMSG_CAN2LIM_CLANGMETRICS WriteMsg::mlNormal, "ClangMetrics processing AST file %s...\n" +#define CMSG_CAN2LIM_CONVERTING WriteMsg::mlNormal, "Converting file: %s ...\n" +#define CMSG_CAN2LIM_FOUND_COMPONENT WriteMsg::mlNormal, "Found component %s ; it's translation units: \n" +#define CMSG_CAN2LIM_FILE_NOT_LOADED WriteMsg::mlWarning, "WARNING: File cannot be loaded (%s)\n" +#define CMSG_CAN2LIM_FILE_NOT_LCSI WriteMsg::mlWarning, "WARNING: File %s is not .lcsi or LinkerCompilationData is not filled! \n" +#define CMSG_CAN2LIM_CONVERTING_ASG_DONE WriteMsg::mlNormal, "Converting %s asg... DONE!\n" +#define CMSG_CAN2LIM_CONVERSION_FINISHED WriteMsg::mlNormal, "Conversion finished!\n" +#define CMSG_CAN2LIM_NO_LCSI_LOADED WriteMsg::mlError, "ERROR: No .lcsi files were loaded or only .csi files were added! \n" +#define CMSG_CAN2LIM_FACTORY_SAVE_ERROR WriteMsg::mlError, "ERROR: %s\n" +#define CMSG_CAN2LIM_FILTER_SAVE_PROBLEM WriteMsg::mlWarning, "WARNING: Error happened during writing file: %s" +#define CMSG_CAN2LIM_LIMML_DUMP_PROBLEM WriteMsg::mlError, "ERROR: Error happened during opening file: %s" +#define CMSG_CAN2LIM_NO_INPUT_FILE WriteMsg::mlError, "ERROR: No input file!" +#define CMSG_CAN2LIM_STATISTICS WriteMsg::mlNormal, "\nStatistics:\n" +#define CMSG_CAN2LIM_CONVERSION_PHASE_TIME WriteMsg::mlNormal, "\tConversion phase time : %10.2fs\n" +#define CMSG_CAN2LIM_METRICS_CALC_TIME WriteMsg::mlNormal, "\tMetrics calcualtion time : %10.2fs\n" +#define CMSG_CAN2LIM_CONVERSION_TIME WriteMsg::mlNormal, "\tConversion time : %10.2fs\n" +#define CMSG_CAN2LIM_AGGREGATION_TIME WriteMsg::mlNormal, "\tAggregation time : %10.2fs\n" +#define CMSG_CAN2LIM_SAVE_TIME WriteMsg::mlNormal, "\tSave asg time : %10.2fs\n" +#define CMSG_CAN2LIM_DUMP_TIME WriteMsg::mlNormal, "\tDump limml time : %10.2fs\n" +#define CMSG_CAN2LIM_TOTAL_TIME WriteMsg::mlNormal, "\tTotal time : %10.2fs\n" +#define CMSG_CAN2LIM_PEAK_MEMORY WriteMsg::mlNormal, "\tPeak memory usage : %10.2fMB\n" +#define CMSG_CAN2LIM_NOT_EXISTED_FILES WriteMsg::mlNormal, "\tNumber of not existed files : %10d\n" + +#define CMSG_CAN2LIM_CANT_LOAD_COMPONENT_FILE WriteMsg::mlError, "Error: Can not load component file: %s\n" +#define CMSG_CAN2LIM_DOUBLE_C_VERSION_NODE WriteMsg::mlDebug, "Double member node on the same location with 'C' language type: Node1:%d Node2:%d\n" +#define CMSG_NOT_AST_FILE WriteMsg::mlError, "The component file contains a not AST file!:%s\n" +#define CMSG_FILE_DOES_NOT_EXIST WriteMsg::mlError, "Error: AST file does not exist! (path:%s)\n" + + +//cpp2lim.cpp messages +#define CMSG_CAN2LIM_ALGORITHMCALLS_START WriteMsg::mlNormal, "Run AlgorithmCalls start...\n" +#define CMSG_CAN2LIM_ALGORITHMCALLS_FINISHED WriteMsg::mlNormal, "Run AlgorithmCalls finished!\n" +#define CMSG_CAN2LIM_CONVERTING_NODES_START WriteMsg::mlNormal, "Converting nodes start...\n" +#define CMSG_CAN2LIM_CONVERTING_NODES_FINISHED WriteMsg::mlNormal, "Converting nodes finished!\n" +#define CMSG_CAN2LIM_COMPILATION_UNIT_WARNING WriteMsg::mlWarning, "WARNING! Compilation unit info is empty at node %d in component %s.\n" + +#define CMSG_CAN2LIM_EX_WRONG_TEMPLATE_PARAMETER "Wrong template parameter type" +#define CMSG_CAN2LIM_EX_INVALID_DECLARATION "Invalid declaration [ " + cpp::asg::Common::toString(decl->getNodeKind()) + " ]" +#define CMSG_CAN2LIM_EX_INVALID_NODEKIND "Invalid NodeKind [ " + cpp::asg::Common::toString(node.getNodeKind()) + " ]" +#define CMSG_CAN2LIM_EX_NL_NOT_NEGATIVE "Nesting level can not be negative!" +#define CMSG_CAN2LIM_EX_NLE_NOT_NEGATIVE "Nesting level ElseIf can not be negative!" + +#define CMSG_CAN2LIM_SOURCERANGE_FILE_MISMATCH WriteMsg::mlWarning, "WARNING! File of the start position (%s) differs from the file of the end position (%s).\n" + +#define CMSG_CAN2LIM_NOLIMNODE_EX(id) "Can not find LIM node for not documentation comment:" + id +#define CMSG_CAN2LIM_NOLIMNODE_WARNING WriteMsg::mlDebug, "WARNING! Can not find LIM node for not documentation comment (%d)!" + +//VisitorAggregated.cpp messages +#define CMSG_CAN2LIM_VISITOR_AGGREGATED WriteMsg::mlNormal, "VisitorAggregated" +#define CMSG_CAN2LIM_VARIANTS_INSIDE_COMPONENT WriteMsg::mlNormal, " for variants inside components" +#define CMSG_CAN2LIM_VARIANTS_BETWEEN_COMPONENT WriteMsg::mlNormal, " for variants between components" +#define CMSG_CAN2LIM_AGGREGATED_START WriteMsg::mlNormal, " start...\n" +#define CMSG_CAN2LIM_AGGREGATED_FINISHED WriteMsg::mlNormal, "VisitorAggregated finished!\n" + + +//VisitorHasMemberCorrector.cpp messages +#define CMSG_CAN2LIM_HAS_MEMBER_START WriteMsg::mlNormal, "VisitorHasMemberCorrector start...\n" +#define CMSG_CAN2LIM_HAS_MEMBER_FINISHED WriteMsg::mlNormal, "VisitorHasMemberCorrector finished!\n" + + +//VisitorNewAggregatedNodeCreator.cpp messages +#define CMSG_CAN2LIM_NEW_AGGREGATE_START WriteMsg::mlNormal, "VisitorNewAggregateNodeCreator start...\n" +#define CMSG_CAN2LIM_NEW_AGGREGATE_FINISHED WriteMsg::mlNormal, "VisitorNewAggregateNodeCreator finished!\n" + +#define CMSG_CAN2LIM_LOCVISITOR_START WriteMsg::mlNormal, "VisitorLOC start...\n" +#define CMSG_CAN2LIM_LOCVISITOR_END WriteMsg::mlNormal, "VisitorLOC finished!\n" + +//Halstead messages +#define CMSG_CAN2LIM_HALSTEAD_VISIT_START WriteMsg::mlNormal, "Halstead visitor start...\n" +#define CMSG_CAN2LIM_HALSTEAD_VISIT_END WriteMsg::mlNormal, "Halstead visitor finished!\n" + +#endif diff --git a/cl/CAN2Lim/src/ASTConversionInfo.cpp b/cl/CAN2Lim/src/ASTConversionInfo.cpp new file mode 100644 index 0000000..83a9156 --- /dev/null +++ b/cl/CAN2Lim/src/ASTConversionInfo.cpp @@ -0,0 +1,210 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + + +#include "../inc/ASTConversionInfo.h" + +#include +#include +#include +#include +#include + +extern std::string g_filterfile; + +using namespace clang; +using namespace std; + +ASTConversionInfo::ASTConversionInfo(const string ASTFilename, const string compilationUnitName, GlobalASTConversionInfo_ThreadSafe& globalInfo, MergeUIDFactory& uidFactory) + : ASTFilename(ASTFilename) + , compilationUnitName(compilationUnitName) + , currentASTIdentifier(compilationUnitName) + , globalInfo(globalInfo) + , uidFactory(uidFactory) +{} + +GlobalASTConversionInfo::GlobalASTConversionInfo(columbus::lim::asg::Factory& limFactory, const clang::metrics::Output& output, columbus::LimOrigin& origin) + : limFactory(limFactory) + , metricsOutput(output) + , limOrigin(origin) + , commentProcessor(*this) + , linker(Linker::getInstance(*this)) +{ +} + +struct ComponentComparator +{ + bool operator()(const columbus::lim::asg::base::Component *lhs, const columbus::lim::asg::base::Component* rhs) const + { + return lhs->getId() < rhs->getId(); + } +}; + +// Filter some folders from LIM if needed +// As folders are added dynamically along the files, so this is the most practical place to do this. +// This traverses all the folders with a stack. +void GlobalASTConversionInfo::filterFolders() +{ + DirectoryFilter directoryFilter; + directoryFilter.openFilterFile(g_filterfile); + + columbus::lim::asg::physical::FileSystem *fs = (columbus::lim::asg::physical::FileSystem*)limFactory.getPointer(limFactory.getFileSystemRoot()); + + if (!fs) return; + + limFactory.setFiltered(fs->getId()); + + for (const auto &kv : canonicalFileNameToFileNode) + { + if (!kv.second) continue; + + if (!directoryFilter.isFilteredOut(kv.first)) + { + limFactory.setNotFilteredThisNode(kv.second->getId()); + } + } +} + +void GlobalASTConversionInfo::finalizeConversion() +{ + filterFolders(); + + for (const auto &kv: linker.component_to_files) + { + auto component = kv.first; + auto files = kv.second; + + unsigned compTLOC = 0, compTLLOC = 0; + for (const auto fileNode : files) + { + component->addFiles(fileNode); //should we filter this too? + + if (limFactory.getIsFiltered(fileNode)) + continue; + + compTLOC += fileNode->getLOC(); + compTLLOC += fileNode->getLLOC(); + } + component->setTLOC(compTLOC); + component->setTLLOC(compTLLOC); + } + + unsigned rootTLOC = 0, rootTLLOC = 0; + for (auto kv : filesAlreadyProcessed) + { + auto fileNode = kv.second; + + if (limFactory.getIsFiltered(fileNode)) + continue; + + rootTLOC += fileNode->getLOC(); + rootTLLOC += fileNode->getLLOC(); + } + + auto root = limFactory.getRoot(); + root->setLOC(rootTLOC); // namespaces will be subtracted below + root->setLLOC(rootTLLOC); + root->setTLOC(rootTLOC); + root->setTLLOC(rootTLLOC); + + auto& rootComponent = limFactory.getComponentRootRef(); + rootComponent.setTLOC(rootTLOC); + rootComponent.setTLLOC(rootTLLOC); + + // As namespace metrics are system level (aggragated above all components), we must deal with them here + for (auto& ns : namespaces) + { + columbus::lim::asg::logical::Package* limPackage = ns.first; + root->setLOC(root->getLOC() - limPackage->getLOC()); + root->setLLOC(root->getLLOC() - limPackage->getLLOC()); + } + + for (auto p : scopeListPerFile) + { + if (!limFactory.getIsFiltered(p.first)) + commentProcessor.bindCommentsToLimTree(p.first); + } + + /*std::cout << "COMMENT TABLE" << std::endl; + for (auto e : commentProcessor.commentTablePerFile) + { + std::cout << "PointerValue:" << e.first << ", File: " << e.first->getName() << ",id = " << e.first->getId() <<", CLOC = " << e.first->getCLOC() << ", cTableEntries = " << e.second.size() << std::endl; + }*/ + + + + + + for (auto kv : limTable) + { + columbus::lim::asg::base::Base* basePtr = kv.second; + if (columbus::lim::asg::logical::Member *memberPtr = dynamic_cast(basePtr)) + { + // Collect all TUs + std::set TUsOfNode; + for (auto it = memberPtr->getIsContainedInListIteratorAssocBegin(); it != memberPtr->getIsContainedInListIteratorAssocEnd(); ++it) + { + columbus::lim::asg::physical::File* filenode = const_cast(&(*it)); + for (auto tuNode : fileNode_to_TUNodes[filenode]) + TUsOfNode.insert(tuNode); + } + + std::set componentsOfNode; + for(auto tuNode : TUsOfNode) + { + // Add the TUs to the node + //memberPtr->addCompilationUnit(tuNode->getId()); + + // In the meantime, collect all components for the TU + for (const auto &component : linker.file_to_components[tuNode]) + componentsOfNode.insert(component); + } + + // Add the components to the node + for(auto component : componentsOfNode) + memberPtr->addBelongsTo(component); + + } + } + linker.link_unresolved_declarations(); + linker.link_unresolved_calls(); + linker.link_unresolved_attribute_accesses(); + +} + +void GlobalASTConversionInfo::addMemberToScopeList(columbus::lim::asg::SourcePosition &position, columbus::lim::asg::logical::Member * member, columbus::lim::asg::physical::File *file) +{ + MyScope scope{ SourcePoint{position.getLine(),position.getColumn()}, + SourcePoint{position.getEndLine(),position.getEndColumn()}, + member}; + scopeListPerFile[file].push_back(ScopeGuard{ scope, ScopeGuard::GuardType::BEGIN }); + scopeListPerFile[file].push_back(ScopeGuard{ scope, ScopeGuard::GuardType::END }); +} + +void GlobalASTConversionInfo::addGlobalNamespaceToScopeList(std::vector &scopeList) +{ + columbus::lim::asg::logical::Member* globalNS = limFactory.getRoot(); + MyScope scope{ SourcePoint{0,0}, + SourcePoint{UINT_MAX, UINT_MAX}, + globalNS}; + scopeList.push_back(ScopeGuard{ scope, ScopeGuard::GuardType::BEGIN }); + scopeList.push_back(ScopeGuard{ scope, ScopeGuard::GuardType::END }); +} + diff --git a/cl/CAN2Lim/src/ASTVisitor.cpp b/cl/CAN2Lim/src/ASTVisitor.cpp new file mode 100644 index 0000000..e228619 --- /dev/null +++ b/cl/CAN2Lim/src/ASTVisitor.cpp @@ -0,0 +1,3136 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "../inc/ASTVisitor.h" +#include "../inc/messages.h" +#include "../inc/clangHelpers.h" + +#include +#include + +#include "clang/Basic/TokenKinds.h" +#include "clang/Lex/Lexer.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + + +using namespace std; + +using namespace clang; +using namespace common; +using namespace tooling; + +using namespace columbus::lim::asg; +using namespace logical; + +using namespace metrics; + +using columbus::FilterState; + + +extern std::string g_filterfile; + + +ASTConverterConsumer::ASTConverterConsumer(ASTConversionInfo& conversionInfo) + : conversionInfo(conversionInfo) +{} + +void ASTConverterConsumer::HandleTranslationUnit(ASTContext& context) +{ + conversionInfo.originMap = columbus::generateNodeIDMaps(context); + auto TUDecl = context.getTranslationUnitDecl(); + if (TUDecl != nullptr) + { + auto printingPolicy = TUDecl->getASTContext().getPrintingPolicy(); + printingPolicy.SuppressInlineNamespace = false; + TUDecl->getASTContext().setPrintingPolicy(printingPolicy); + + ASTConverterVisitor visitor(context, conversionInfo); + visitor.TraverseDecl(TUDecl); + + map sortedFiles; + for (auto it = context.getSourceManager().fileinfo_begin(); it != context.getSourceManager().fileinfo_end(); ++it) + { + const clang::FileEntry* fileEntry = it->first; + sortedFiles.insert(make_pair(fileEntry->getUniqueID(), fileEntry)); + } + + for(auto it : sortedFiles) + visitor.getOrCreateFileNode(it.second); + + + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + globalInfo.commentProcessor.loadCommentStructure(conversionInfo.ASTFilename); + }); + + } +} + +/////////// VISITORS //////////////////////////////////////////////////////////// + +ASTConverterVisitor::ASTConverterVisitor(ASTContext& context, ASTConversionInfo& conversionInfo) + : myFilter(g_filterfile, context, true, true, true) + , context (context) + , conversionInfo (conversionInfo) + , sm (context.getSourceManager()) +{ + if (context.getLangOpts().CPlusPlus) + languageKind = columbus::lim::asg::lnkCpp; + else if (context.getLangOpts().ObjC) + languageKind = columbus::lim::asg::lnkNotSet; // TODO Create a new language kind for the ObjC sources + else + languageKind = columbus::lim::asg::lnkC; +} + +// This is only a test to see performance. Not correct behaviour +bool ASTConverterVisitor::TraverseDecl(clang::Decl *decl) +{ + if(!decl) + return true; + + // Check if this is a decl for a file we want to traverse + const FileEntry *fileEntry = sm.getFileEntryForID(locToFileID(decl->getLocation())); + if (fileEntry) + { + getOrCreateFileNode(fileEntry); + if (conversionInfo.filesOfTU.count(fileEntry) == 0) + return true; + } + + RecursiveASTVisitor::TraverseDecl(decl); + return true; +} + +bool ASTConverterVisitor::VisitTranslationUnitDecl(const clang::TranslationUnitDecl* decl) +{ + // This looks useless, but we must do this, as it has the side effect of sm.fileinfo getting filled with the .h files (a cache table is being built in the background) + sm.getExpansionLineNumber(sm.getLocForEndOfFile(sm.getMainFileID())); + + // Add translation unit. + pMyCurrentTU = getOrCreateFileNode(sm.getFileEntryForID(sm.getMainFileID())); + string fileName = pMyCurrentTU->getName(); + + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + globalInfo.fileNode_to_TUNodes[pMyCurrentTU].insert(pMyCurrentTU); + conversionInfo.pCurrentASTFile = &globalInfo.limFactory.createFile(conversionInfo.ASTFilename); + globalInfo.limFactory.setFiltered(conversionInfo.pCurrentASTFile->getId()); + + //Add compilationunit edges for components + for (const auto& component : globalInfo.componentsOfTU[conversionInfo.currentASTIdentifier]) + { + if (!contains(component->getCompilationUnitListIteratorBegin(), component->getCompilationUnitListIteratorEnd(), conversionInfo.pCurrentASTFile)) + component->addCompilationUnit(conversionInfo.pCurrentASTFile); + } + }); + + return true; +} + +bool ASTConverterVisitor::VisitVarDecl(const clang::VarDecl* decl) +{ + //common::WriteMsg::write(common::WriteMsg::mlNormal, "DAVID: visiting vardecl\n"); + // We are only interested in global variables and declarations in function bodys here. + // Note: If this is changed, be sure to also update parameters (ParmVarDecl) in VisitFunctionDecl() as it depends + // on the fact that parameters are not handled here. + if (ParmVarDecl::classof(decl)) + return true; + + // If the varDecl is in a function, then we add it as instantiates edge + if (const FunctionDecl* f = dyn_cast_or_null(decl->getParentFunctionOrMethod())) + { + //cout << f->getNameAsString() << endl; + //decl->getType().getTypePtr()->dump(); + addInstantiatesEdge(f, decl->getType().getTypePtr()); + return true; + } + + if(isTemplateInstantiation(decl->getTemplateSpecializationKind())) + return true; + + // Otherwise it is an attribute + Attribute* limAttribute; + shared_ptr uid = conversionInfo.uidFactory.create(decl, conversionInfo.pMyMangleContext); + + //cout << "AAAAAAAAAAAAAAAAAAttribute UID : " << uid->getName() << endl; + + // Node + bool nodeCreated = createNode(uid, limAttribute, decl); + //limAttribute->addCompilationUnit(pMyCurrentTU); + + if (!nodeCreated) + return true; + + limAttribute->setMangledName(static_cast(*uid).getMangledName()); + limAttribute->setIsStatic(decl->getStorageClass() == StorageClass::SC_Static || decl->isStaticDataMember()); + limAttribute->setLanguage(languageKind); + switch (decl->getAccess()) + { + case AccessSpecifier::AS_public: limAttribute->setAccessibility(AccessibilityKind::ackPublic); break; + case AccessSpecifier::AS_protected: limAttribute->setAccessibility(AccessibilityKind::ackProtected); break; + case AccessSpecifier::AS_private: limAttribute->setAccessibility(AccessibilityKind::ackPrivate); break; + default: limAttribute->setAccessibility(AccessibilityKind::ackNone); break; + } + + // Edges + addPositionEdge(limAttribute, decl); + + if (const Decl *parent = dyn_cast_or_null(decl->getDeclContext())) + { + addMemberEdge(parent, limAttribute); + } + + //It should belong to logical parent, not physical, so this code is not needed + /*if (const Decl* parent = getParentFromContext(decl)) + { + if (DeclContext::classof(parent)) + addMemberEdge(parent, limAttribute); + }*/ + + if (limAttribute->getTypeIsEmpty()) + { + const Type* type = decl->getType().getTypePtr(); + //type->dump(); + ConvertType(type); + + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + auto it = globalInfo.typeTable.find(conversionInfo.uidFactory.createTypeId(QualType(type, 0), conversionInfo.pMyMangleContext)); + if (it != globalInfo.typeTable.end()) + limAttribute->addType(it->second); + }); + + } + + if (decl->hasInit()) + addUsesEdgeForStmt(limAttribute, decl->getInit()); + + // Filter if required. + if (myFilter.getFilterState(toVoid(decl)) == FilterState::Filtered) + { + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + globalInfo.limFactory.setFiltered(limAttribute->getId()); + }); + } + + return true; +} + +bool ASTConverterVisitor::VisitFieldDecl(const clang::FieldDecl* decl) +{ + Attribute* limAttribute; + shared_ptr uid = conversionInfo.uidFactory.create(decl, conversionInfo.pMyMangleContext); + + // Node + bool nodeCreated = createNode(uid, limAttribute, decl); + //limAttribute->addCompilationUnit(pMyCurrentTU); + + if (!nodeCreated) + return true; + + limAttribute->setMangledName(static_cast(*uid).getMangledName()); + limAttribute->setLanguage(languageKind); + + if (const ObjCIvarDecl* ivar = dyn_cast_or_null(decl)) + { + switch (ivar->getAccessControl()) + { + case ObjCIvarDecl::AccessControl::Public: limAttribute->setAccessibility(AccessibilityKind::ackPublic); break; + case ObjCIvarDecl::AccessControl::Protected: limAttribute->setAccessibility(AccessibilityKind::ackProtected); break; + case ObjCIvarDecl::AccessControl::Private: limAttribute->setAccessibility(AccessibilityKind::ackPrivate); break; + case ObjCIvarDecl::AccessControl::None: limAttribute->setAccessibility(AccessibilityKind::ackNone); break; + default: limAttribute->setAccessibility(AccessibilityKind::ackNone); break; + } + } + else + { + switch (decl->getAccess()) + { + case AccessSpecifier::AS_public: limAttribute->setAccessibility(AccessibilityKind::ackPublic); break; + case AccessSpecifier::AS_protected: limAttribute->setAccessibility(AccessibilityKind::ackProtected); break; + case AccessSpecifier::AS_private: limAttribute->setAccessibility(AccessibilityKind::ackPrivate); break; + default: limAttribute->setAccessibility(AccessibilityKind::ackNone); break; + } + } + + // Edges + addPositionEdge(limAttribute, decl); + + const Decl* parentDecl; + if (const ObjCIvarDecl* iVar = dyn_cast(decl)) + parentDecl = iVar->getContainingInterface(); + else + parentDecl = decl->getParent(); + + addMemberEdge(parentDecl, limAttribute); + + if (limAttribute->getTypeIsEmpty()) + { + const Type* type = decl->getType().getTypePtr(); + ConvertType(type); + + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + auto it = globalInfo.typeTable.find(conversionInfo.uidFactory.createTypeId(QualType(type, 0), conversionInfo.pMyMangleContext)); + if (it != globalInfo.typeTable.end()) + limAttribute->addType(it->second); + }); + + } + + // Filter if required. + if (myFilter.getFilterState(toVoid(decl)) == FilterState::Filtered) + { + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + globalInfo.limFactory.setFiltered(limAttribute->getId()); + }); + } + + return true; +} + +bool ASTConverterVisitor::VisitEnumConstantDecl(const clang::EnumConstantDecl* decl) +{ + Attribute* limAttribute; + shared_ptr uid = conversionInfo.uidFactory.create(decl, conversionInfo.pMyMangleContext); + + // Node + bool nodeCreated = createNode(uid, limAttribute, decl); + //limAttribute->addCompilationUnit(pMyCurrentTU); + + if (!nodeCreated) + return true; + + limAttribute->setMangledName(static_cast(*uid).getMangledName()); + limAttribute->setLanguage(languageKind); + limAttribute->setAccessibility(ackPublic); + + // Edges + addPositionEdge(limAttribute, decl); + + if (const Decl* parent = getParentFromContext(decl)) + addMemberEdge(parent, limAttribute); + + if (limAttribute->getTypeIsEmpty()) + { + const Type* type = decl->getType().getTypePtr(); + ConvertType(type); + + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + auto it = globalInfo.typeTable.find(conversionInfo.uidFactory.createTypeId(QualType(type, 0), conversionInfo.pMyMangleContext)); + if (it != globalInfo.typeTable.end()) + limAttribute->addType(it->second); + }); + + } + + // Filter if required. + if (myFilter.getFilterState(toVoid(decl)) == FilterState::Filtered) + { + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + globalInfo.limFactory.setFiltered(limAttribute->getId()); + }); + } + + return true; +} + +bool ASTConverterVisitor::VisitNamespaceDecl(const clang::NamespaceDecl* decl) +{ + Package* limPackage; + shared_ptr uid = conversionInfo.uidFactory.create(decl, conversionInfo.pMyMangleContext); + + // Node + if (!createNode(uid, limPackage, decl)) + { + // Only add position edge if it does not exist yet for this file. + clang::SourceLocation loc = decl->getLocation(); + if (loc.isValid()) + { + // At this point, file MUST exist and not nullptr + columbus::lim::asg::physical::File *file = getFileNode(sm.getFileEntryForID(locToFileID(loc))); + if (!file) + { + WriteMsg::write(WriteMsg::mlDDebug, "Namespacefile ERROR, file with hash (%s) and name (%s) does not exist, but it should\n", locToFileID(loc).getHashValue(), sm.getFilename(loc).str().c_str()); + } + else + { + columbus::lim::asg::SourcePosition position = getSourcePosition(decl); + for (auto it = limPackage->getIsContainedInListIteratorAssocBegin(); it != limPackage->getIsContainedInListIteratorAssocEnd(); ++it) + { + if (it->getId() == file->getId()) + { + if (it.getAssocClass() == position) + return true; + } + } + + limPackage->addIsContainedIn(file, position); + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + globalInfo.addMemberToScopeList(position, limPackage, file); + }); + } + } + + return true; + } + + limPackage->setMangledName(static_cast(*uid).getMangledName()); + limPackage->setLanguage(languageKind); + limPackage->setAccessibility(AccessibilityKind::ackNone); + limPackage->setIsAnonymous(decl->isAnonymousNamespace()); + + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + globalInfo.namespaces.push_back(std::make_pair(limPackage, uid)); + }); + + const NamespaceMetrics* metrics = nullptr; + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + metrics = globalInfo.metricsOutput.getNamespaceMetrics(*uid); + }); + // If this is the first time the namespace is visited then get it's metrics from the metricsOutput. + if (metrics) + { + clang::metrics::NamespaceMetrics::RangeMetrics filteredMetrics; + + // Loop through all namespace ranges and filter ones appearing in filtered files. + auto metricsByFile = metrics->metricsByFile; + bool allRangesInFilteredFiles = true; + for (auto it = metricsByFile.begin(); it != metricsByFile.end(); it++) + { + // Get the file name. + string canonicalFileName = common::pathCanonicalize(it->first); + // Get the metrics for this namespace range. + clang::metrics::NamespaceMetrics::RangeMetrics rangeMetrics = it->second; + + // If the file is not filtered, add the metrics to the filtered total. + if (!myFilter.getDirectoryFilter().isFilteredOut(canonicalFileName)) + { + filteredMetrics += rangeMetrics; + allRangesInFilteredFiles = false; + } + + + } + limPackage->setLOC(filteredMetrics.LOC); + limPackage->setTLOC(filteredMetrics.TLOC); + limPackage->setLLOC(filteredMetrics.LLOC); + limPackage->setTLLOC(filteredMetrics.TLLOC); + + if (allRangesInFilteredFiles || myFilter.getFilterState(toVoid(decl)) == FilterState::Filtered) + { + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + globalInfo.limFactory.setFiltered(limPackage->getId()); + }); + } + } + + // Edges + addPositionEdge(limPackage, decl); + addMemberEdge(dyn_cast(decl->getParent()), limPackage); + + return true; +} + +bool ASTConverterVisitor::VisitRecordDecl(const clang::RecordDecl* decl) +{ + //this is a visitor for c style structs and unions only + if(isa(decl)) + return true; + + Class* limClass; + shared_ptr uid = conversionInfo.uidFactory.create(decl, conversionInfo.pMyMangleContext); + + bool nodeCreated = createNode(uid, limClass, decl); + + if (!nodeCreated) + return true; + + RecordDeclHelper(decl,limClass,uid); + return true; +} + +bool ASTConverterVisitor::VisitCXXRecordDecl(const clang::CXXRecordDecl* decl) +{ + shared_ptr uid = conversionInfo.uidFactory.create(decl, conversionInfo.pMyMangleContext); + buildClass(decl, uid); + return true; +} + +bool ASTConverterVisitor::VisitEnumDecl(const clang::EnumDecl* decl) +{ + Class* limClass; + shared_ptr uid = conversionInfo.uidFactory.create(decl, conversionInfo.pMyMangleContext); + + bool nodeCreated = createNode(uid, limClass, decl); + //limClass->addCompilationUnit(pMyCurrentTU); + + if (!nodeCreated) + return true; + + limClass->setMangledName(static_cast(*uid).getMangledName()); + limClass->setLanguage(languageKind); + limClass->setClassKind(ClassKind::clkEnum); + limClass->setIsAnonymous(decl->getDeclName().isEmpty()); + + switch (decl->getAccess()) + { + case AccessSpecifier::AS_public: limClass->setAccessibility(AccessibilityKind::ackPublic); break; + case AccessSpecifier::AS_protected: limClass->setAccessibility(AccessibilityKind::ackProtected); break; + case AccessSpecifier::AS_private: limClass->setAccessibility(AccessibilityKind::ackPrivate); break; + default: limClass->setAccessibility(AccessibilityKind::ackPublic); break; + } + + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + if (const EnumMetrics* metrics = globalInfo.metricsOutput.getEnumMetrics(*uid)) + { + limClass->setLOC(metrics->LOC); + limClass->setTLOC(metrics->LOC); + limClass->setLLOC(metrics->LLOC); + limClass->setTLLOC(metrics->LLOC); + } + }); + + // Edges + addPositionEdge(limClass, decl); + addMemberEdge(dyn_cast(decl->getParent()), limClass); + + // Filter if required. + if (myFilter.getFilterState(toVoid(decl)) == FilterState::Filtered) + { + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + globalInfo.limFactory.setFiltered(limClass->getId()); + }); + } + + return true; +} + +bool ASTConverterVisitor::VisitClassScopeFunctionSpecializationDecl(const clang::ClassScopeFunctionSpecializationDecl* decl) +{ + //clang::manuallyExpandClassScopeFunctionSpecializationDecl(decl,context); //hack + //set usedTypes; + return true; +} + +bool ASTConverterVisitor::VisitFunctionDecl(const clang::FunctionDecl* decl) +{ + if (isa(decl)) + return true; + + buildMethod(decl); + return true; +} + +bool ASTConverterVisitor::VisitFriendDecl(const clang::FriendDecl* decl) +{ + // Only handle type friends here. Friend functions are handled in VisitFunctionDecl(). + if (const CXXRecordDecl* parentClass = dyn_cast_or_null(getParentFromContext(decl))) + { + // This is only true for non-function friends. + if (const TypeSourceInfo* tsi = decl->getFriendType()) + { + if (const Type* type = tsi->getType().getTypePtrOrNull()) + { + // Load the LIM node of the parent class (in which the friend is declared). + // Ensure the node is of Class type. + Class* limParent = getOrCreateIncompleteNode_Class(parentClass); + if (!limParent) + return true; + + if (const CXXRecordDecl* classDecl = type->getAsCXXRecordDecl()) + { + // We create a node for the friend declaration (this is a very special kind of node...) + shared_ptr uid = conversionInfo.uidFactory.create(decl, conversionInfo.pMyMangleContext); + Class* limFriendClass = buildClass(classDecl, uid); + + if (limFriendClass) + { + addPositionEdge(limFriendClass, decl); + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + globalInfo.linker.add_declaration(limFriendClass, uid); + if (myFilter.getFilterState(toVoid(decl)) == FilterState::Filtered) + globalInfo.limFactory.setFiltered(limFriendClass->getId()); + else + globalInfo.limFactory.setNotFiltered(limFriendClass->getId()); + }); + } + + //we apply the friend edge to the definition if we can, otherwise just to the declaration created above + if (const CXXRecordDecl *def = classDecl->getDefinition()) + { + Class* limDefClass = getOrCreateIncompleteNode_Class(def); + if(limDefClass) + addFriendshipEdge(limParent, limDefClass->getId(), classDecl->getNameAsString()); + } + else if (limFriendClass) + { + addFriendshipEdge(limParent, limFriendClass->getId(), classDecl->getNameAsString()); + } + } + else if (const TemplateTypeParmType* pt = dyn_cast_or_null(type)) + { + if (const TemplateTypeParmDecl* named = pt->getDecl()) + addFriendshipEdge(limParent, 0, named->getNameAsString()); + } + } + } + } + + return true; +} + +bool ASTConverterVisitor::VisitTypedefNameDecl(const clang::TypedefNameDecl *decl) +{ + if(Scope *limParent = getOrCreateIncompleteNode_Scope(getParentFromContext(decl))) + addUsesEdgeForType(limParent,context.getTypedefType(decl).getTypePtr()); + return true; +} + +bool ASTConverterVisitor::VisitExpr(const clang::Expr* expr) +{ + + /*cout << "Expr Type found: "<< expr->getType()->getTypeClassName() << ", " << conversionInfo.uidFactory.createTypeId(expr->getType())->getName() << ", "; + if (const BuiltinType* specificType = expr->getType()->getAs()) + { + cout << specificType->getNameAsCString(PrintingPolicy(context.getLangOpts())); + } + cout << endl;*/ + + if(isa(expr)) + return true; + + if (const clang::FunctionDecl* f = dyn_cast_or_null(getFunctionContextFromStmt(*expr))) + if (Method* limMethod = getOrCreateIncompleteNode_Method(f)) { + //expr->dump(); + addUsesEdgeForStmt(limMethod, expr, false); + } + + + return true; +} + +bool ASTConverterVisitor::VisitCallExpr(const clang::CallExpr* stmt) +{ + const FunctionDecl *directCallee = stmt->getDirectCallee(); + const FunctionDecl *caller = dyn_cast_or_null(getFunctionContextFromStmt(*stmt)); + + HandleFunctionCalling(directCallee, caller, stmt); + + if (caller && directCallee) + { + Method* limCaller = getOrCreateIncompleteNode_Method(caller); + if(limCaller) + addUsesEdgeForType(limCaller, directCallee->getType().getTypePtrOrNull()); + } + return true; +} + +bool ASTConverterVisitor::VisitCXXThrowExpr(const clang::CXXThrowExpr* stmt) +{ + if (!stmt->getSubExpr()) + return true; + + if (const FunctionDecl* fd = dyn_cast_or_null(getFunctionContextFromStmt(*stmt))) + { + const Type* type = stmt->getSubExpr()->getType().getTypePtr(); + ConvertType(type); + + Method* limMethod = getOrCreateIncompleteNode_Method(fd); + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + auto it2 = globalInfo.typeTable.find(conversionInfo.uidFactory.createTypeId(QualType(type, 0), conversionInfo.pMyMangleContext)); + if (limMethod && it2 != globalInfo.typeTable.end()) + limMethod->addThrows(it2->second); + }); + + } + + return true; +} + +bool ASTConverterVisitor::VisitCXXConstructExpr(const clang::CXXConstructExpr* stmt) +{ + if (const CXXConstructorDecl* constDecl = stmt->getConstructor()) + { + if (const CXXRecordDecl* record = constDecl->getParent()) + { + if (const FunctionDecl* func = dyn_cast_or_null(getFunctionContextFromStmt(*stmt))) + { + if (!constDecl->isImplicit()) + { + HandleFunctionCalling(dyn_cast_or_null(constDecl), func, stmt); + } + + if(stmt->getConstructionKind() == CXXConstructExpr::ConstructionKind::CK_Complete) + addInstantiatesEdge(func, record->getTypeForDecl()); + } + } + } + + return true; +} + +bool ASTConverterVisitor::VisitDeclRefExpr(const clang::DeclRefExpr* stmt) +{ + if (const clang::FunctionDecl* f = dyn_cast_or_null(getFunctionContextFromStmt(*stmt))) + { + if (auto tmp = stmt->getQualifier()) + { + if (auto rec = tmp->getAsRecordDecl()) + { + Method *limMethod = getOrCreateIncompleteNode_Method(f); + if(limMethod) + addUsesEdgeForType(limMethod, rec->getTypeForDecl()); + } + } + handleAttributeAccess(stmt->getDecl(), f); + } + + return true; +} + +bool ASTConverterVisitor::VisitMemberExpr(const clang::MemberExpr* stmt) +{ + handleAttributeAccess(stmt->getMemberDecl(), dyn_cast_or_null(getFunctionContextFromStmt(*stmt))); + return true; +} + +bool ASTConverterVisitor::TraverseLambdaExpr(clang::LambdaExpr* stmt) +{ + // TODO: Lambdas get filtered! Fix that! + TraverseCXXMethodDecl(stmt->getCallOperator()); + RecursiveASTVisitor::TraverseLambdaExpr(stmt); + return true; +} + +/////////// OBJ-C VISITORS //////////////////////////////////////////////////////////// + +bool ASTConverterVisitor::VisitObjCInterfaceDecl(clang::ObjCInterfaceDecl* decl) +{ + Class* limClass; + shared_ptr uid = conversionInfo.uidFactory.create(decl, conversionInfo.pMyMangleContext); + + bool nodeCreated = createNode(uid, limClass, decl); + + if (nodeCreated) + { + limClass->setMangledName(static_cast(*uid).getMangledName()); + limClass->setLanguage(columbus::lim::asg::lnkNotSet); // TODO create lnkObjC + limClass->setIsAnonymous(decl->getDeclName().isEmpty()); + limClass->setClassKind(ClassKind::clkClass); + limClass->setAccessibility(AccessibilityKind::ackNone); + limClass->setIsAbstract(false); + + if (const ObjCObjectType * baseType = decl->getSuperClassType()) + { + ConvertType(baseType); + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + auto it = globalInfo.typeTable.find(conversionInfo.uidFactory.createTypeId(QualType(baseType, 0), conversionInfo.pMyMangleContext)); + if (it != globalInfo.typeTable.end()) + limClass->addIsSubclass(it->second); + }); + } + + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + if (const ClassMetrics* metrics = globalInfo.metricsOutput.getClassMetrics(*uid)) + { + limClass->setLOC(metrics->LOC); + limClass->setTLOC(metrics->TLOC); + limClass->setLLOC(metrics->LLOC); + limClass->setTLLOC(metrics->TLLOC); + } + }); + } + + // Get protocols this Interface implements. + SmallVector protocols; + SmallVector ProtocolLocs; + ObjCCategoryDecl::protocol_loc_iterator FromProtoLoc = decl->protocol_loc_begin(); + + for (ObjCProtocolDecl::protocol_iterator FromProto = decl->protocol_begin(), + FromProtoEnd = decl->protocol_end(); + FromProto != FromProtoEnd; + ++FromProto, + ++FromProtoLoc) + { + protocols.push_back(*FromProto); + ProtocolLocs.push_back(*FromProtoLoc); + } + if(decl->hasDefinition()) + { + decl->setProtocolList(protocols.data(), protocols.size(), ProtocolLocs.data(), context); + for (const ObjCProtocolDecl* p : protocols) + { + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + auto it = globalInfo.limTable.find(conversionInfo.uidFactory.create(p, conversionInfo.pMyMangleContext)); + if (it != globalInfo.limTable.end()) + { + Class* protocol = static_cast(it->second); + protocol->addExtends(limClass); + } + }); + } + } + + // Edges + addPositionEdge(limClass, decl); + addMemberEdge(dyn_cast(decl->getParent()), limClass); + limClass->addCompilationUnit(pMyCurrentTU); + + // Uses edge for definitions. + if (decl->getDefinition() == decl) + { + iterateDecls(decl, limClass); + } + + // Filter if required. + if (myFilter.getFilterState(toVoid(decl)) == FilterState::Filtered) + { + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + globalInfo.limFactory.setFiltered(limClass->getId()); + }); + } + return true; +} + +bool ASTConverterVisitor::VisitObjCMethodDecl(const clang::ObjCMethodDecl* decl) +{ + Method* limMethod; + shared_ptr uid = conversionInfo.uidFactory.create(decl, conversionInfo.pMyMangleContext); + bool nodeCreated; + nodeCreated = createNode(uid, limMethod, decl); + + assert(uid && "Sanity check: Variable should be always non-null at this point."); + + if (nodeCreated) + { + limMethod->setMangledName(static_cast(*uid).getMangledName()); + limMethod->setLanguage(columbus::lim::asg::lnkNotSet); // TODO create lnkObjC + limMethod->setMethodKind(MethodKind::mekNormal); + + // TODO: Might not need this check. + if (const ObjCMethodDecl* md = dyn_cast(decl)) + { + limMethod->setAccessibility(AccessibilityKind::ackNone); + limMethod->setIsStatic(md->isClassMethod()); + } + + const FunctionMetrics* metrics; + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + metrics = globalInfo.metricsOutput.getFunctionMetrics(*uid); + }); + if (metrics) + { + limMethod->setLOC(metrics->LOC); + limMethod->setTLOC(metrics->TLOC); + limMethod->setLLOC(metrics->LLOC); + limMethod->setTLLOC(metrics->TLLOC); + limMethod->setDistinctOperands(metrics->HD_Operands); + limMethod->setDistinctOperators(metrics->HD_Operators); + limMethod->setTotalOperands(metrics->H_Operands); + limMethod->setTotalOperators(metrics->H_Operators); + + // Note: Despite calling it "number of branches", it really is McCC (number of branches + 1). + limMethod->setNumberOfBranches(metrics->McCC); + } + } + + // Edges + addPositionEdge(limMethod, decl); + limMethod->addCompilationUnit(pMyCurrentTU); + + const DeclContext* parent = decl->getParent(); + + if(const ObjCCategoryImplDecl* impl = dyn_cast(parent)) + { + parent = impl->getCategoryDecl(); + } + else if(const ObjCImplementationDecl* impl = dyn_cast(parent)) + { + parent = impl->getClassInterface(); + } + + addMemberEdge(dyn_cast(parent), limMethod); + + // Add return type if not yet set up. + if (limMethod->getReturnsIsEmpty()) + { + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + auto it = globalInfo.typeTable.find(conversionInfo.uidFactory.createTypeId(QualType(decl->getReturnType().getTypePtr(), 0), conversionInfo.pMyMangleContext)); + if (it != globalInfo.typeTable.end()) + limMethod->addReturns(it->second); + }); + } + + // No need to do anything with params if they're already added - possibly from different compilation unit (CU). + // TODO: This check is probably nolonger required as declarations and definitions nolonger share the same node. + if (limMethod->getParameterSize() != decl->param_size()) + { + // Add the parameters here. + // Important: No node duplication is possible. ParmVarDecl is indeed a VarDecl, so VisitVarDecl() visits it. + // But in VisitVarDecl() we only handle global variable declarations. No node is created there for parameters. + for (const ParmVarDecl* param : decl->parameters()) + { + ConvertType(param->getType().getTypePtr()); + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + Parameter* limParam = globalInfo.limFactory.createParameterNode(); + limParam->setName(param->getNameAsString()); + + auto it = globalInfo.typeTable.find(conversionInfo.uidFactory.createTypeId(QualType(param->getType().getTypePtr(), 0), conversionInfo.pMyMangleContext)); + if (it != globalInfo.typeTable.end()) + limParam->setType(it->second); + limMethod->addParameter(limParam); + }); + } + } + + // Uses edge for definitions. + if (decl->isThisDeclarationADefinition()) + { + const Type* t; + for (const Decl* d : decl->decls()) + { + // Ignore implicit code. + if (d->isImplicit()) + continue; + + if (const ValueDecl* td = dyn_cast(d)) + t = td->getType().getTypePtrOrNull(); + else if (const TypeDecl* td = dyn_cast(d)) + t = td->getTypeForDecl(); + else + continue; + + if (t) + addUsesEdgeForType(limMethod, t); + } + } + + // Filter if required. + if (myFilter.getFilterState(toVoid(decl)) == FilterState::Filtered) + { + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + globalInfo.limFactory.setFiltered(limMethod->getId()); + }); + } + + return true; +} + +bool ASTConverterVisitor::VisitObjCProtocolDecl(clang::ObjCProtocolDecl* decl) +{ + Class* limClass; + shared_ptr uid = conversionInfo.uidFactory.create(decl, conversionInfo.pMyMangleContext); + bool nodeCreated = createNode(uid, limClass, decl); + + if (nodeCreated) + { + limClass->setMangledName(static_cast(*uid).getMangledName()); + limClass->setLanguage(columbus::lim::asg::lnkNotSet); // TODO create lnkObjC + limClass->setIsAnonymous(decl->getDeclName().isEmpty()); + limClass->setClassKind(ClassKind::clkProtocol); + limClass->setAccessibility(AccessibilityKind::ackNone); + limClass->setIsAbstract(true); + + SmallVector protocols; + SmallVector ProtocolLocs; + ObjCCategoryDecl::protocol_loc_iterator FromProtoLoc = decl->protocol_loc_begin(); + + for (ObjCProtocolDecl::protocol_iterator FromProto = decl->protocol_begin(), + FromProtoEnd = decl->protocol_end(); + FromProto != FromProtoEnd; + ++FromProto, + ++FromProtoLoc) + { + protocols.push_back(*FromProto); + ProtocolLocs.push_back(*FromProtoLoc); + } + + if(decl->hasDefinition()) + { + decl->setProtocolList(protocols.data(), protocols.size(), ProtocolLocs.data(), context); + for (const ObjCProtocolDecl* p : protocols) + { + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + auto it = globalInfo.limTable.find(conversionInfo.uidFactory.create(p, conversionInfo.pMyMangleContext)); + if (it != globalInfo.limTable.end()) + { + Class* ancestorProtocol = static_cast(it->second); + globalInfo.limFactory.beginType(); + globalInfo.limFactory.addTypeFormer(globalInfo.limFactory.createTypeFormerType(ancestorProtocol->getId()).getId()); + type::Type& artificialProtocolType = globalInfo.limFactory.endType(); + + limClass->addIsSubclass(artificialProtocolType.getId()); + } + }); + } + } + + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + if (const ClassMetrics* metrics = globalInfo.metricsOutput.getClassMetrics(*uid)) + { + limClass->setLOC(metrics->LOC); + limClass->setTLOC(metrics->TLOC); + limClass->setLLOC(metrics->LLOC); + limClass->setTLLOC(metrics->TLLOC); + } + }); + } + + // Edges + addPositionEdge(limClass, decl); + addMemberEdge(dyn_cast(decl->getParent()), limClass); + limClass->addCompilationUnit(pMyCurrentTU); + + // Uses edge for definitions. + if (decl->getDefinition() == decl) + { + iterateDecls(decl, limClass); + } + + // Filter if required. + if (myFilter.getFilterState(toVoid(decl)) == FilterState::Filtered) + { + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + globalInfo.limFactory.setFiltered(limClass->getId()); + }); + } + return true; +} + +bool ASTConverterVisitor::VisitObjCCategoryDecl(const clang::ObjCCategoryDecl* decl) +{ + Class* limClass; + shared_ptr uid = conversionInfo.uidFactory.create(decl, conversionInfo.pMyMangleContext); + bool nodeCreated = createNode(uid, limClass, decl); + + if (nodeCreated) + { + limClass->setMangledName(static_cast(*uid).getMangledName()); + limClass->setLanguage(columbus::lim::asg::lnkNotSet); // TODO create lnkObjC + limClass->setIsAnonymous(decl->getDeclName().isEmpty()); + limClass->setAccessibility(AccessibilityKind::ackNone); + limClass->setIsAbstract(false); + + if (decl->IsClassExtension()) + limClass->setClassKind(ClassKind::clkExtension); + else + limClass->setClassKind(ClassKind::clkCategory); + + const ClassMetrics* metrics; + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + metrics = globalInfo.metricsOutput.getClassMetrics(*uid); + }); + if (metrics) + { + limClass->setLOC(metrics->LOC); + limClass->setTLOC(metrics->TLOC); + limClass->setLLOC(metrics->LLOC); + limClass->setTLLOC(metrics->TLLOC); + } + } + + // Edges + addPositionEdge(limClass, decl); + addMemberEdge(dyn_cast(decl->getParent()), limClass); + limClass->addCompilationUnit(pMyCurrentTU); + + if (const ObjCInterfaceDecl * extendedInterface = decl->getClassInterface()) + { + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + Class* extendedClass = static_cast(globalInfo.limTable.at(conversionInfo.uidFactory.create(extendedInterface, conversionInfo.pMyMangleContext))); + limClass->addExtends(extendedClass); + }); + } + + // Uses edge for definitions. + iterateDecls(decl, limClass); + + // Filter if required. + if (myFilter.getFilterState(toVoid(decl)) == FilterState::Filtered) + { + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + globalInfo.limFactory.setFiltered(limClass->getId()); + }); + } + return true; +} + +bool ASTConverterVisitor::VisitObjCPropertyDecl(const clang::ObjCPropertyDecl* decl) +{ + if (const ObjCMethodDecl* method = decl->getGetterMethodDecl()) + VisitObjCMethodDecl(method); + if (const ObjCMethodDecl* method = decl->getSetterMethodDecl()) + VisitObjCMethodDecl(method); + return true; +} + +bool ASTConverterVisitor::VisitObjCMessageExpr(const clang::ObjCMessageExpr* stmt) +{ + const ObjCMethodDecl* caller = dyn_cast_or_null(getFunctionContextFromStmt(*stmt)); + return HandleFunctionCalling(stmt->getMethodDecl(), caller, stmt); +} + +bool ASTConverterVisitor::VisitObjCAtThrowStmt(const clang::ObjCAtThrowStmt* stmt) +{ + if (!stmt->getThrowExpr()) + return true; + + if (const ObjCMethodDecl* decl = dyn_cast_or_null(getFunctionContextFromStmt(*stmt))) + { + const Type* type = stmt->getThrowExpr()->getType().getTypePtr(); + ConvertType(type); + + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + auto it1 = globalInfo.limTable.find(conversionInfo.uidFactory.create(decl, conversionInfo.pMyMangleContext)); + auto it2 = globalInfo.typeTable.find(conversionInfo.uidFactory.createTypeId(QualType(type, 0), conversionInfo.pMyMangleContext)); + if (it1 != globalInfo.limTable.end() && it2 != globalInfo.typeTable.end()) + { + if (Method* limMethod = dynamic_cast(it1->second)) + { + limMethod->addThrows(it2->second); + } + } + }); + + } + + return true; +} + +/////////// HELPERS //////////////////////////////////////////////////////////// + +/////////// CLASS-HELPERS ////////////////////////////////////////////////////// + +void ASTConverterVisitor::RecordDeclHelper(const clang::RecordDecl* decl, Class* limClass, shared_ptr uid) +{ + limClass->setMangledName(static_cast(*uid).getMangledName()); + limClass->setIsAnonymous(decl->getDeclName().isEmpty()); + limClass->setLanguage(languageKind); + limClass->setAccessibility(AccessibilityKind::ackPublic); //c type stuff is public by default + + switch (decl->getTagKind()) + { + case TagTypeKind::TTK_Class: limClass->setClassKind(ClassKind::clkClass); break; + case TagTypeKind::TTK_Struct: limClass->setClassKind(ClassKind::clkStruct); break; + case TagTypeKind::TTK_Union: limClass->setClassKind(ClassKind::clkUnion); break; + case TagTypeKind::TTK_Interface: limClass->setClassKind(ClassKind::clkInterface); break; + case TagTypeKind::TTK_Enum: limClass->setClassKind(ClassKind::clkEnum); break; + } + + const ClassMetrics* metrics; + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + metrics = globalInfo.metricsOutput.getClassMetrics(*uid); + }); + if (metrics) + { + limClass->setLOC(metrics->LOC); + limClass->setTLOC(metrics->TLOC); + limClass->setLLOC(metrics->LLOC); + limClass->setTLLOC(metrics->TLLOC); + } + + // Edges + shared_ptr recordUID = conversionInfo.uidFactory.create(decl, conversionInfo.pMyMangleContext); + + if(recordUID->equals(*uid)) // For friendDecls the UID is created from the friendDecl not the recordDecl and positionEdge is handled elsewhere. + addPositionEdge(limClass, decl); + if(isa(decl)) + addMemberEdge(dyn_cast(decl->getParent()), limClass); + else + addMemberEdge(decl->getTranslationUnitDecl(), limClass); // c typed nested structs and unions are always global + + + // Uses edge for definitions. + /*if (decl->getDefinition() == decl) + { + iterateDecls(decl, limClass); + }*/ + + //cout << (string)decl->getName() << endl; + // Filter if required. + if (myFilter.getFilterState(toVoid(decl)) == FilterState::Filtered) + { + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + globalInfo.limFactory.setFiltered(limClass->getId()); + }); + } +} + +void ASTConverterVisitor::CXXRecordDeclHelper(const clang::CXXRecordDecl* decl, Class* limClass, shared_ptr uid) +{ + RecordDeclHelper(decl,limClass,uid); + + /* + limClass->setMangledName(static_cast(*uid).getMangledName()); + limClass->setIsAnonymous(decl->getDeclName().isEmpty()); + limClass->setLanguage(columbus::lim::asg::lnkCpp); + switch (decl->getTagKind()) + { + case TagTypeKind::TTK_Class: limClass->setClassKind(ClassKind::clkClass); break; + case TagTypeKind::TTK_Struct: limClass->setClassKind(ClassKind::clkStruct); break; + case TagTypeKind::TTK_Union: limClass->setClassKind(ClassKind::clkUnion); break; + case TagTypeKind::TTK_Interface: limClass->setClassKind(ClassKind::clkInterface); break; + case TagTypeKind::TTK_Enum: limClass->setClassKind(ClassKind::clkEnum); break; + } + */ + if (decl->hasDefinition()) + { + limClass->setIsAbstract(decl->isAbstract()); + + if (metrics::isInterface(decl)) + { + limClass->setClassKind(ClassKind::clkInterface); + limClass->setIsAbstract(true); + } + + for (const CXXBaseSpecifier base : decl->bases()) + { + const Type* baseType = base.getType().getTypePtr(); + ConvertType(baseType); + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + auto it = globalInfo.typeTable.find(conversionInfo.uidFactory.createTypeId(QualType(baseType, 0), conversionInfo.pMyMangleContext)); + if (it != globalInfo.typeTable.end()) + limClass->addIsSubclass(it->second); + }); + } + } + + switch (decl->getAccess()) + { + case AccessSpecifier::AS_public: limClass->setAccessibility(AccessibilityKind::ackPublic); break; + case AccessSpecifier::AS_protected: limClass->setAccessibility(AccessibilityKind::ackProtected); break; + case AccessSpecifier::AS_private: limClass->setAccessibility(AccessibilityKind::ackPrivate); break; + // for some reason this must default to public (for the metrics to treat the function as API) + default: limClass->setAccessibility(AccessibilityKind::ackPublic); break; + } + /* + if (const ClassMetrics* metrics = conversionInfo.metricsOutput.getClassMetrics(*uid)) + { + limClass->setLOC(metrics->LOC); + limClass->setTLOC(metrics->TLOC); + limClass->setLLOC(metrics->LLOC); + limClass->setTLLOC(metrics->TLLOC); + } + + // Edges + addPositionEdge(limClass, decl); + addMemberEdge(dyn_cast(decl->getParent()), limClass); + // Uses edge for definitions. + if (decl->getDefinition() == decl) + { + iterateDecls(decl, limClass); + } + + // Filter if required. + if (myFilter.getFilterState(toVoid(decl)) == FilterState::Filtered) + conversionInfo.limFactory.setFiltered(limClass->getId()); + */ +} + +logical::Class* ASTConverterVisitor::buildClassGenericSpec(const ClassTemplateSpecializationDecl* decl, std::shared_ptr uid) +{ + Class *limClass; + // Specialization. + bool nodeCreated = createNode(uid, limClass, decl); + //limClass->addCompilationUnit(pMyCurrentTU); + + if (!nodeCreated) + return nullptr; + + const Decl* templatedDecl = decl->getSpecializedTemplate()->getTemplatedDecl(); + shared_ptr primUID = conversionInfo.uidFactory.create(templatedDecl, conversionInfo.pMyMangleContext); + ClassGeneric* mg; + createNode(primUID, mg, templatedDecl); + static_cast(limClass)->setSpecialize(mg); + + // Filter if required. + if (myFilter.getFilterState(toVoid(templatedDecl)) == FilterState::Filtered) + { + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + globalInfo.limFactory.setFiltered(limClass->getId()); + }); + } + + const TemplateArgumentList& args = decl->getTemplateInstantiationArgs(); + for (unsigned i = 0; i < args.size(); ++i) + addTemplateArgumentEdge(args[i], static_cast(limClass)); + + CXXRecordDeclHelper(decl, limClass, uid); + return limClass; +} + +logical::Class* ASTConverterVisitor::buildClassGeneric(const ClassTemplateDecl* templateDecl, std::shared_ptr uid) { + const CXXRecordDecl *decl = templateDecl->getTemplatedDecl(); + + Class *limClass; + bool nodeCreated = createNode(uid, limClass, decl); + //limClass->addCompilationUnit(pMyCurrentTU); + + if (!nodeCreated) + return nullptr; + + // Add template parameters. + for (const NamedDecl* param : templateDecl->getTemplateParameters()->asArray()) + static_cast(limClass)->addGenericParameter(createGenericParameter(param)); + + CXXRecordDeclHelper(decl, limClass, uid); + return limClass; +} + +logical::Class* ASTConverterVisitor::buildClass(const CXXRecordDecl* decl, std::shared_ptr uid) +{ + //cout << "Built class " << decl->getNameAsString() << endl; + if (const ClassTemplateDecl* templateDecl = decl->getDescribedClassTemplate()) + { + return buildClassGeneric(templateDecl, uid); + } + else if (const ClassTemplateSpecializationDecl* spec = dyn_cast(decl)) + { + if (spec->getSpecializationKind() == TSK_ExplicitSpecialization) + return buildClassGenericSpec(spec, uid); + } + else if (!decl->getTemplateInstantiationPattern()) + { + // Default case: this is a "normal" class that has nothing to do with templates. + Class* limClass; + bool nodeCreated = createNode(uid, limClass, decl); + + //limClass->addCompilationUnit(pMyCurrentTU); + + if (!nodeCreated) + return nullptr; + + CXXRecordDeclHelper(decl, limClass, uid); + return limClass; + } + return nullptr; +} + +/////////// METHOD-HELPERS ///////////////////////////////////////////////////// + +// Automatically deduces the proper method type to build +bool ASTConverterVisitor::buildMethod(const FunctionDecl* decl) { + const CXXRecordDecl *recordParent = dyn_cast_or_null(decl->getParent()); + + if (const FunctionTemplateDecl* templateDecl = decl->getDescribedFunctionTemplate()) + buildMethodGeneric(decl,templateDecl); + else if (const FunctionTemplateDecl *primary = decl->getPrimaryTemplate()) + { + if(decl->getTemplateSpecializationKind() == TemplateSpecializationKind::TSK_ExplicitSpecialization) + buildMethodGenericSpec(decl,primary); + } + else if (const FunctionTemplateSpecializationInfo *ftsi = decl->getTemplateSpecializationInfo()) + { + if(const FunctionTemplateDecl *ftd = ftsi->getTemplate()) + buildMethodGenericSpec(decl,ftd); + } + else if(!decl->isTemplateInstantiation() && recordParent && recordParent->isLambda()) + buildLambda(recordParent); + else if(!decl->isTemplateInstantiation()) + buildSimpleMethod(decl); + return true; +} + +bool ASTConverterVisitor::buildSimpleMethod(const FunctionDecl* decl) { + Method* limMethod; + bool nodeCreated; + set usedTypes; + + shared_ptr uid = conversionInfo.uidFactory.create(decl, conversionInfo.pMyMangleContext); + nodeCreated = createNode(uid, limMethod, decl); + + if(!nodeCreated) + return false; + + methodBuildCommon(decl, limMethod, uid, nodeCreated, usedTypes); + return true; +} + +bool ASTConverterVisitor::buildMethodGeneric(const FunctionDecl* decl, const FunctionTemplateDecl* templateDecl) +{ + Method* limMethod; + shared_ptr uid = conversionInfo.uidFactory.create(decl, conversionInfo.pMyMangleContext); + bool nodeCreated; + set usedTypes; + + nodeCreated = createNode(uid, limMethod, decl); + + if(!nodeCreated) + return false; + + // Add template parameters. + for (const NamedDecl* param : templateDecl->getTemplateParameters()->asArray()) + static_cast(limMethod)->addGenericParameter(createGenericParameter(param)); + + methodBuildCommon(decl, limMethod, uid, nodeCreated, usedTypes); + return true; +} + +bool ASTConverterVisitor::buildMethodGenericSpec(const FunctionDecl* specFunc, const FunctionTemplateDecl* templateDecl) { + if(const FunctionTemplateDecl *original = templateDecl->getInstantiatedFromMemberTemplate()) + templateDecl = original; + + Method* limMethod; + shared_ptr uid = conversionInfo.uidFactory.create(specFunc, conversionInfo.pMyMangleContext); + set usedTypes; + + //cout << uid->getName() << endl; + bool nodeCreated = createNode(uid, limMethod, specFunc); + if (nodeCreated) + { + MethodGenericSpec* limSpec = static_cast(limMethod); + shared_ptr primUID = conversionInfo.uidFactory.create(templateDecl->getAsFunction(), conversionInfo.pMyMangleContext); + + MethodGeneric* mg; + createNode(primUID, mg, specFunc); + limSpec->setSpecialize(mg); + + const TemplateArgumentList *tArgList = specFunc->getTemplateSpecializationArgs(); + + for (unsigned i = 0; i < tArgList->size(); ++i){ + addTemplateArgumentEdge(tArgList->operator[](i), limSpec); + } + methodBuildCommon(specFunc, limMethod, uid, nodeCreated, usedTypes); + } + + return true; +} + +bool ASTConverterVisitor::buildLambda(const clang::CXXRecordDecl* lambdaClass) +{ + bool nodeCreated = true; + set usedTypes; + + const CXXMethodDecl* decl = lambdaClass->getLambdaCallOperator(); + shared_ptr uid = conversionInfo.uidFactory.create(decl, conversionInfo.pMyMangleContext); + + Method* limMethod; + nodeCreated = createNode(uid, limMethod, decl); + + if (!nodeCreated) + return false; + + methodBuildCommon(decl, limMethod, uid, nodeCreated, usedTypes); + limMethod->setIsAnonymous(true); + limMethod->setMethodKind(MethodKind::mekNormal); + limMethod->setName("lambda"); + addMemberEdge(dyn_cast_or_null(lambdaClass->getParent()), limMethod); + return true; +} + +void ASTConverterVisitor::methodBuildCommon(const clang::FunctionDecl* decl, Method* limMethod, shared_ptr uid, bool nodeCreated, set usedTypes, bool isLambda) +{ + assert(uid && "Sanity check: Variable should be always non-null at this point."); + + if (!nodeCreated) + return; + + limMethod->setMangledName(static_cast(*uid).getMangledName()); + limMethod->setLanguage(languageKind); + + if (decl->isOverloadedOperator()) + limMethod->setMethodKind(MethodKind::mekOperator); + + if (decl->getStorageClass() == StorageClass::SC_Static) + limMethod->setIsStatic(true); + + if (decl->isOverloadedOperator()) + limMethod->setMethodKind(MethodKind::mekOperator); + else + limMethod->setMethodKind(MethodKind::mekNormal); + + if (const CXXMethodDecl* md = dyn_cast(decl)) + { + switch (md->getAccess()) + { + case AccessSpecifier::AS_public: limMethod->setAccessibility(AccessibilityKind::ackPublic); break; + case AccessSpecifier::AS_protected: limMethod->setAccessibility(AccessibilityKind::ackProtected); break; + case AccessSpecifier::AS_private: limMethod->setAccessibility(AccessibilityKind::ackPrivate); break; + default: limMethod->setAccessibility(AccessibilityKind::ackNone); break; + } + + limMethod->setIsStatic(md->isStatic()); + limMethod->setIsVirtual(md->isVirtual()); + limMethod->setIsAbstract(md->isPure()); + + if (CXXConstructorDecl::classof(md)) + limMethod->setMethodKind(MethodKind::mekConstructor); + else if (CXXDestructorDecl::classof(md)) + limMethod->setMethodKind(MethodKind::mekDestructor); + else if (isGetter(limMethod->getName())) + limMethod->setMethodKind(MethodKind::mekGet); + else if (isSetter(limMethod->getName())) + limMethod->setMethodKind(MethodKind::mekSet); + } + else + { + limMethod->setAccessibility(AccessibilityKind::ackNone); + } + + const FunctionMetrics* metrics; + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + metrics = globalInfo.metricsOutput.getFunctionMetrics(*uid); + }); + if (metrics) + { + limMethod->setLOC(metrics->LOC); + limMethod->setTLOC(metrics->TLOC); + limMethod->setLLOC(metrics->LLOC); + limMethod->setTLLOC(metrics->TLLOC); + limMethod->setDistinctOperands(metrics->HD_Operands); + limMethod->setDistinctOperators(metrics->HD_Operators); + limMethod->setTotalOperands(metrics->H_Operands); + limMethod->setTotalOperators(metrics->H_Operators); + limMethod->setNumberOfStatements(metrics->NOS); + limMethod->setNestingLevel(metrics->NL); + limMethod->setNestingLevelElseIf(metrics->NLE); + + // Note: Despite calling it "number of branches", it really is McCC (number of branches + 1). + limMethod->setNumberOfBranches(metrics->McCC); + } + + // Edges + addPositionEdge(limMethod, decl); + if(!isLambda) + addMemberEdge(dyn_cast(decl->getParent()), limMethod); + + // Add return type if not yet set up. + if (limMethod->getReturnsIsEmpty()) + { + //cout << decl->getNameAsString() << endl; + //decl->getReturnType()->dump(); + + /*if (const AutoType *at = dyn_cast_or_null(decl->getReturnType().getTypePtr())) { + at->getDeducedType()->dump(); + }*/ + ConvertType(decl->getReturnType().getTypePtr()); + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + auto it = globalInfo.typeTable.find(conversionInfo.uidFactory.createTypeId(QualType(decl->getReturnType().getTypePtr(), 0), conversionInfo.pMyMangleContext)); + if (it != globalInfo.typeTable.end()) + limMethod->addReturns(it->second); + }); + + /* + ConvertType(decl->getReturnType().getTypePtr()); + auto it = conversionInfo.typeTable.find(conversionInfo.uidFactory.createTypeId(QualType(decl->getReturnType().getTypePtr(), 0))); + if (it != conversionInfo.typeTable.end()) + limMethod->addReturns(it->second);*/ + } + + usedTypes.insert(decl->getReturnType().getTypePtr()); + + // No need to do anything with params if they're already added - possibly from different compilation unit (CU). + // TODO: This check is probably nolonger required as declarations and definitions nolonger share the same node. + if (limMethod->getParameterSize() != decl->param_size()) + { + // Add the parameters here. + // Important: No node duplication is possible. ParmVarDecl is indeed a VarDecl, so VisitVarDecl() visits it. + // But in VisitVarDecl() we only handle global variable declarations. No node is created there for parameters. + for (const ParmVarDecl* param : decl->parameters()) + { + Parameter* limParam; + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + limParam = globalInfo.limFactory.createParameterNode(); + }); + limParam->setName(param->getNameAsString()); + + if (param->getType()->isPointerType() || param->getType()->isReferenceType()) + limParam->setParamKind(ParameterKind::pmkInOut); + else + limParam->setParamKind(ParameterKind::pmkIn); + + ConvertType(param->getType().getTypePtr()); + usedTypes.insert(param->getType().getTypePtr()); + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + auto it = globalInfo.typeTable.find(conversionInfo.uidFactory.createTypeId(QualType(param->getType().getTypePtr(), 0), conversionInfo.pMyMangleContext)); + if (it != globalInfo.typeTable.end()) + limParam->setType(it->second); + }); + + limMethod->addParameter(limParam); + } + } + + // Add friend edge to parent class if this is a friend function. + if (const FriendDecl* fd = dyn_cast_or_null(getParentFromContext(decl))) + if (const CXXRecordDecl* parent = dyn_cast_or_null(getParentFromContext(fd))) + if (Class *limParentClass = getOrCreateIncompleteNode_Class(parent)) + { + const FunctionDecl* def = decl->getDefinition(); + Method *limDef = nullptr; + if (def) + limDef = getOrCreateIncompleteNode_Method(def); + + if(limDef) + addFriendshipEdge(limParentClass, limDef->getId(), decl->getNameAsString()); + else + addFriendshipEdge(limParentClass, limMethod->getId(), decl->getNameAsString()); + } + + // Uses edge for definitions. + if (decl->getDefinition() == decl) + { + const Type* t; + for (const Decl* d : decl->decls()) + { + // Ignore implicit code. + //if (d->isImplicit()) + // continue; + if (const ValueDecl* td = dyn_cast(d)) + t = td->getType().getTypePtrOrNull(); + else if (const TypeDecl* td = dyn_cast(d)) + t = td->getTypeForDecl(); + else + continue; + + if (t && (usedTypes.find(t) == usedTypes.end())) + addUsesEdgeForType(limMethod, t); + } + } + + // Filter if required. + if (myFilter.getFilterState(toVoid(decl)) == FilterState::Filtered) + { + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + globalInfo.limFactory.setFiltered(limMethod->getId()); + }); + } + + //nem tudom, hogy van-e értelme itt fájlon belül ezt intézni, mert a linkernek ugyis dolgoznia kell a fájlon kivüli deklaráció-definíció feloldásokkal + /* + if (!decl->isThisDeclarationADefinition()) + { + cout << decl->getNameAsString() << endl; + int a; + buildMethod(decl->getDefinition()); + shared_ptr defUID = conversionInfo.uidFactory.create(decl); + auto defIt = conversionInfo.limTable.find(defUID); + if (defIt != conversionInfo.limTable.end()) { + limMethod->setDeclares(dynamic_cast(defIt->second)); + } + }*/ +} + +/////////// OTHER ///////////////////////////////////////////////////////////// + +void ASTConverterVisitor::iterateDecls(const clang::Decl* decl, Class* limClass) +{ + const Type* t; + for (const Decl* d : dyn_cast(decl)->decls()) + { + // Ignore implicit code. + if (d->isImplicit()) + continue; + + if (const ValueDecl* td = dyn_cast(d)) + t = td->getType().getTypePtrOrNull(); + else if (const TypedefDecl* td = dyn_cast(d)) + t = context.getTypedefType(td).getTypePtr(); + else if (const TypeDecl* td = dyn_cast(d)) + t = td->getTypeForDecl(); + else + continue; + + if (dyn_cast(d)) + continue; + + if (dyn_cast(d)) + continue; + + if (dyn_cast(d)) + continue; + + if (t) + { + if (const CXXRecordDecl* recordDecl = dyn_cast_or_null(decl)) + { + if (t == recordDecl->getTypeForDecl()) + continue; + } + addUsesEdgeForType(limClass, t); + } + } +} + +template +bool ASTConverterVisitor::HandleFunctionCalling(const CallType* callee, const CallType* caller, const clang::Stmt* stmt) +{ + // Helper lambda. + auto hasCallsAlready = [](auto node, columbus::NodeId callId) + { + for (auto it = node->getCallsListIteratorBegin(); it != node->getCallsListIteratorEnd(); ++it) + { + if (it->getId() == callId) + return true; + } + + return false; + }; + + // Forward declare pointer to node. + MethodCall* limCall = nullptr; + + if (callee) + { + if(callee->isImplicit()) + return false; + + if (isDefinition(callee)) + { + // Try to create 'MethodCall' node by direct callee. + Method *limCallee = nullptr; + if(const FunctionDecl *fd = dyn_cast_or_null(callee)) + limCallee = getOrCreateIncompleteNode_Method(fd); + else + limCallee = getOrCreateIncompleteNode(callee); + + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + if (limCallee) + limCall = &globalInfo.limFactory.createMethodCall(limCallee->getId()); + else + limCall = &globalInfo.limFactory.createMethodCall(getImprint(stmt)); + }); + } + } + else + { + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + limCall = &globalInfo.limFactory.createMethodCall(getImprint(stmt)); // Imprint if no callee is available + }); + } + + // Ensure we have a caller to which the function call can be connected. + // Note that a 'MethodCall' is created regardless of whether the caller is known or not. + if (caller) + { + Method *limCaller = nullptr; + if(const FunctionDecl *fd = dyn_cast_or_null(caller)) + limCaller = getOrCreateIncompleteNode_Method(fd); + else + limCaller = getOrCreateIncompleteNode(caller); + + if (limCaller) + { + if (callee && !isDefinition(callee)) + { + shared_ptr uid = conversionInfo.uidFactory.create(callee, conversionInfo.pMyMangleContext); + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + globalInfo.linker.unresolved_calls.push_back(std::pair, columbus::lim::asg::base::Base*>(std::static_pointer_cast(uid), limCaller)); + }); + } + else if (limCall && !hasCallsAlready(limCaller, limCall->getId())) + { + limCaller->addCalls(limCall); + } + } + } + + // Check whether this function is used to initialize a variable. + const Decl* decl = getDeclFromStmt(*stmt); + while (decl && !(VarDecl::classof(decl) || FieldDecl::classof(decl))) + { + decl = getParentFromContext(decl); + } + + // Found a (member) variable declaration. Add calls edge. + // Skip if Decl is a ParmVarDecl, as we don't mangle them anyway. + // Example: void bar(int = foo()); + if (decl && !isa(decl) && !decl->getParentFunctionOrMethod()) + { + Attribute *limAttribute = getOrCreateIncompleteNode(decl); + if (limAttribute) + { + if (callee && !isDefinition(callee)) + { + shared_ptr calleeUID = conversionInfo.uidFactory.create(callee, conversionInfo.pMyMangleContext); + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + globalInfo.linker.unresolved_calls.push_back(std::pair, columbus::lim::asg::base::Base*>(std::static_pointer_cast(calleeUID), limAttribute)); + }); + } + else + { + if (limCall && !hasCallsAlready(limAttribute, limCall->getId())) + { + limAttribute->addCalls(limCall); + } + } + } + } + + return true; +} + +std::string ASTConverterVisitor::getImprint(const Stmt* stmt) +{ + SourceManager& sm = context.getSourceManager(); + + // Get the source code (aka the function call) at this position. + SourceRange r = stmt->getSourceRange(); + llvm::StringRef ref = Lexer::getSourceText(CharSourceRange(r, true), sm, LangOptions()); + return ref.str(); +} + +bool ASTConverterVisitor::ConvertType(const clang::Type* type) +{ + //type->dump(); + // debug + /*cout << "?????????????Converting type: " << type->getTypeClassName() << ", "; + if (const BuiltinType* specificType = type->getAs()) + { + cout << specificType->getNameAsCString(PrintingPolicy(context.getLangOpts())); + } + cout << "lol" << endl;*/ + + // We want Types to be visited only once! + auto insertionResult = myVisitedTypes.insert(type); + + if (!insertionResult.second) + return true; + + shared_ptr uid = conversionInfo.uidFactory.createTypeId(QualType(type, 0), conversionInfo.pMyMangleContext); + // The ID can be null if the mangler is unable to generate a mangled name for it. + if (!uid) + return true; + + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + auto it = globalInfo.typeTable.find(uid); + if (it != globalInfo.typeTable.end()) + return; + + globalInfo.limFactory.beginType(); + createLIMType(type); + type::Type& limType = globalInfo.limFactory.endType(); + globalInfo.typeTable.emplace(uid, &limType); + }); + + return true; +} + +template +T* ASTConverterVisitor::getOrCreateIncompleteNode(const clang::Decl* decl) +{ + shared_ptr uid = conversionInfo.uidFactory.create(decl, conversionInfo.pMyMangleContext); + T* limNode = nullptr; + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + bool nodeCreated = createNode(uid, limNode, decl); + + if(nodeCreated) + globalInfo.incompleteNodes.insert(uid); + }); + + return limNode; +} + +Method * ASTConverterVisitor::getOrCreateIncompleteNode_Method(const clang::FunctionDecl * decl) +{ + if (isa(decl)) + return nullptr; + + if (decl->getDescribedFunctionTemplate()) + return getOrCreateIncompleteNode(decl); + else if (decl->getPrimaryTemplate()) + { + if(decl->getTemplateSpecializationKind() == TemplateSpecializationKind::TSK_ExplicitSpecialization) + return getOrCreateIncompleteNode(decl); + } + else if (const FunctionTemplateSpecializationInfo *ftsi = decl->getTemplateSpecializationInfo()) + { + if(ftsi->getTemplate()) + return getOrCreateIncompleteNode(decl); + } + else if(!decl->isTemplateInstantiation()) + return getOrCreateIncompleteNode(decl); + + return nullptr; +} + +columbus::lim::asg::logical::Class * ASTConverterVisitor::getOrCreateIncompleteNode_Class(const clang::CXXRecordDecl * decl) +{ + if (decl->getDescribedClassTemplate()) + { + return getOrCreateIncompleteNode(decl); + } + else if (const ClassTemplateSpecializationDecl* spec = dyn_cast(decl)) + { + if (spec->getSpecializationKind() == TSK_ExplicitSpecialization) + return getOrCreateIncompleteNode(decl); + } + else if (!decl->getTemplateInstantiationPattern()) + { + return getOrCreateIncompleteNode(decl); + } + return nullptr; +} + +columbus::lim::asg::logical::Scope * ASTConverterVisitor::getOrCreateIncompleteNode_Scope(const clang::Decl * decl) +{ + if (const FunctionDecl *fd = dyn_cast_or_null(decl)) + return getOrCreateIncompleteNode_Method(fd); + else if(const CXXRecordDecl *cxxrd = dyn_cast_or_null(decl)) + return getOrCreateIncompleteNode_Class(cxxrd); + else if(const RecordDecl *rd = dyn_cast_or_null(decl)) + return getOrCreateIncompleteNode(rd); + else if(const NamespaceDecl *nd = dyn_cast_or_null(decl)) + return getOrCreateIncompleteNode(nd); + else if(const EnumDecl *ed = dyn_cast_or_null(decl)) + return getOrCreateIncompleteNode(ed); + else + return nullptr; +} + +template bool ASTConverterVisitor::createNode(std::shared_ptr uid, U*& out, const Decl* decl) +{ + if(decl && decl->isImplicit()) + return false; + + bool isCreated; + + columbus::lim::asg::base::Base* limNode = nullptr; + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + auto it = globalInfo.limTable.find(uid); + if (it != globalInfo.limTable.end()) + limNode = it->second; + + if (!limNode) + { + out = createNodeHelper(); + globalInfo.limTable.emplace(uid, out); + + if (decl) + { + auto it = conversionInfo.originMap->node2id.find((void*)decl); + if (it != conversionInfo.originMap->node2id.end()) + { + assert(pMyCurrentTU && "TU should already be set at this point."); + globalInfo.limOrigin.addCompIdCppIdLimIdToMap(conversionInfo.pCurrentASTFile->getId(), it->second, out->getId()); + } + + if (const NamedDecl* nd = dyn_cast(decl)) + { + out->setName(nd->getNameAsString()); + //if (out->getName() == "") + // out->setName(""); + + std::string s; + llvm::raw_string_ostream ss(s); + + // For functions, demangled the mangled name. + if (const FunctionDecl *fd = dyn_cast_or_null(nd)) + { + if (const CXXConstructorDecl *ccd = dyn_cast(decl)) + { + out->setName(ccd->getParent()->getNameAsString()); + conversionInfo.pMyMangleContext->mangleName(GlobalDecl(cast(ccd), CXXCtorType::Ctor_Complete), ss); + } + else if (const CXXDestructorDecl *dcd = dyn_cast(decl)) + { + out->setName("~" + dcd->getParent()->getNameAsString()); + conversionInfo.pMyMangleContext->mangleName(GlobalDecl(cast(dcd), CXXDtorType::Dtor_Complete), ss); + } + else + conversionInfo.pMyMangleContext->mangleName(fd, ss); + + size_t bufferSize = 200; + char* buffer = (char*)malloc(bufferSize); + int status; + buffer = llvm::itaniumDemangle(ss.str().c_str(), buffer, &bufferSize, &status); + + if (status == 0 && buffer) + { + string demangledName(buffer); + if (const CXXRecordDecl *rd = dyn_cast_or_null(fd->getParent())) + { + // Make some alterations to the demangled lambda names + if (rd->isLambda()) + { + std::regex pattern("('lambda[0-9]*'(\\(.*?\\))*)|(\\$_[0-9]*)"); + demangledName = std::regex_replace(demangledName, pattern, "lambda"); + } + } + out->setDemangledName(demangledName); + } + else + { + out->setDemangledName("problem"); + + std::string s_t; + llvm::raw_string_ostream ss_t(s_t); + fd->getNameForDiagnostic(ss_t, context.getPrintingPolicy(), true); + + ss_t << "("; + if (const FunctionType *ft = fd->getFunctionType()) + { + if (const FunctionProtoType *fpt = dyn_cast_or_null(ft)) + { + bool first = true; + for (auto pt : fpt->param_types()) + { + if (first) + first = false; + else + ss_t << ","; + + ss_t << pt.getAsString(context.getPrintingPolicy()); + } + } + } + ss_t << ")"; + out->setDemangledName(ss_t.str()); + } + } + else + { + // Use the same name as we'd use for diagnostics. + nd->getNameForDiagnostic(ss, context.getPrintingPolicy(), true); + out->setDemangledName(ss.str()); + } + if (out->getDemangledName() == "") + { + out->setDemangledName("(anonymous)"); + } + } + + // these are the types of decls that have Declares edges in the LIM + if(TagDecl::classof(decl) || FunctionDecl::classof(decl) || VarDecl::classof(decl)) + { + if (isDefinition(decl)) + globalInfo.linker.add_definition(out, uid); + else + globalInfo.linker.add_declaration(out, uid); + } + } + isCreated = true; + } + else + { + //this part is reached if the node is already created + out = static_cast(limNode); + + if (globalInfo.incompleteNodes.erase(uid) > 0) + { + // The node is already in the LIM table, but it's incomplete. In such case we return true, so that the rest of the build finishes. + // We also delete it, as it will be soon completed + isCreated = true; + } + else + { + isCreated = false; + } + } + }); + return isCreated; +} + +columbus::lim::asg::physical::File* ASTConverterVisitor::getOrCreateFileNode(const clang::FileEntry* fileEntry) +{ + if (!fileEntry) + return nullptr; + + // If this file have already been seen in the CURRENT AST, we simply return it, there is nothing else to do + auto itFile = conversionInfo.filesOfTU.find(fileEntry); + if (itFile != conversionInfo.filesOfTU.end()) + return itFile->second; + + // If it isn't, there are 2 cases: + columbus::lim::asg::physical::File* file; + + // If we've never seen this file before (not even in previous AST conversions), we must create the file node and set it's properties + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + auto itFile2 = globalInfo.filesAlreadyProcessed.find(fileEntry->getUniqueID()); + if (itFile2 == globalInfo.filesAlreadyProcessed.end()) + file = createFileNode(fileEntry); + else + file = itFile2->second; + + // If the file has already been added during the conversion of a previous AST, we don't need to create the file node, but + // in both cases, we need to register the file for the current AST, and components. + + //Do the registerings + for (const auto& component : globalInfo.componentsOfTU[conversionInfo.currentASTIdentifier]) + { + globalInfo.linker.component_to_files[component].insert(file); + globalInfo.linker.file_to_components[file].insert(component); + } + + if(pMyCurrentTU) + globalInfo.fileNode_to_TUNodes[file].insert(pMyCurrentTU); + }); + + return file; +} + +columbus::lim::asg::physical::File* ASTConverterVisitor::getFileNode(const clang::FileEntry *fileEntry) +{ + if(!fileEntry) + return nullptr; + + auto itFile = conversionInfo.filesOfTU.find(fileEntry); + if (itFile == conversionInfo.filesOfTU.end()) + { + columbus::lim::asg::physical::File* file = nullptr; + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + auto itFile2 = globalInfo.filesAlreadyProcessed.find(fileEntry->getUniqueID()); + if (!(itFile2 == globalInfo.filesAlreadyProcessed.end())) + file = itFile2->second; + }); + return file; + } + else + { + return itFile->second; + } +} + +columbus::lim::asg::physical::File* ASTConverterVisitor::createFileNode(const clang::FileEntry* fileEntry) +{ + if (!fileEntry) + return nullptr; + + string filename = fileEntry->getName().str(); + //cout << "file created with name : " << filename << endl; + + // We have special needs for what the filename should look like in the LIM + // (also, the filter uses absolute path(canonical), while in the LIM, we might want to use relative) + string canonicalFileName = common::pathCanonicalize(filename); + string LIMLongname; + if (filename.empty()) + LIMLongname = ""; // all stuff that is in an unknown file will be under this name + else + LIMLongname = cANFilePathRenamer.changeToLIMCompatible(canonicalFileName); + + columbus::lim::asg::physical::File* fileNode; + + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + fileNode = &globalInfo.limFactory.createFile(LIMLongname); + + unsigned endLine = 0, endColumn = 0; + if (auto fileMetrics = globalInfo.metricsOutput.getFileMetrics(filename)) + { + fileNode->setLOC(fileMetrics->LOC); + fileNode->setLLOC(fileMetrics->LLOC); + fileNode->setNumberOfBranches(fileMetrics->McCC); + endLine = fileMetrics->endLine; + endColumn = fileMetrics->endColumn; + //CLOC will be set in finalizeTU (for that, the commentProcessor have to read the comments from the .comment files) + } + + columbus::lim::asg::Package* root = globalInfo.limFactory.getRoot(); + if (!contains(root->getIsContainedInListIteratorAssocBegin(), root->getIsContainedInListIteratorAssocEnd(), fileNode)) + { + // Add new 'IsContainedIn' edge in root for this file + root->addIsContainedIn(fileNode, SourcePosition(relDefines, 1, 1, endLine, endColumn)); + } + + conversionInfo.filesOfTU[fileEntry] = fileNode; + globalInfo.filesAlreadyProcessed.insert(make_pair(fileEntry->getUniqueID(), fileNode)); + + // For the comments lookup + string correctedFilename = canonicalFileName; + if (globalInfo.changePathFrom.c_str() && globalInfo.changePathTo.c_str()) + correctedFilename = common::replace(correctedFilename.c_str(), globalInfo.changePathFrom.c_str(), globalInfo.changePathTo.c_str()); + + globalInfo.correctedFileNameToFileNode[correctedFilename] = fileNode; + globalInfo.canonicalFileNameToFileNode[canonicalFileName] = fileNode; + }); + //cout << "File added to comment map: " << common::replace(filename.c_str(), conversionInfo.changePathFrom.c_str(), conversionInfo.changePathTo.c_str()) << endl; + + // Filtering is in the post-process (ASTConversionInfo.cpp/FilterFolders()) + + //cout << "CREATED FILENAME = "<< filename << " FILEUniqueID = " << fileEntry->getUniqueID().getDevice() << ":" << fileEntry->getUniqueID().getFile() <<" FILEUID = " << fileEntry->getUID() << endl; + + return fileNode; +} + +clang::FileID ASTConverterVisitor::locToFileID(const clang::SourceLocation &loc) +{ + if(loc.isMacroID()) + return sm.getFileID(sm.getExpansionLoc(loc)); // we need this, as for code in macros, the spellingloc has no file attached to it + else + return sm.getFileID(loc); +} + + +columbus::lim::asg::GenericParameter* ASTConverterVisitor::createGenericParameter(const clang::NamedDecl* param) +{ + // Create parameter node in LIM. + GenericParameter* limParam; + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + limParam = globalInfo.limFactory.createGenericParameterNode(); + }); + limParam->setName(param->getNameAsString()); + + // Choose parameter type. + if (const TemplateTypeParmDecl* d = dyn_cast(param)) + { + limParam->setGenericParameterKind(d->isParameterPack() ? gpkTypePack : gpkType); + + // Register in LIM table. + shared_ptr uid = conversionInfo.uidFactory.create(param, conversionInfo.pMyMangleContext); + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + if (globalInfo.limTable.find(uid) == globalInfo.limTable.end()) + globalInfo.limTable.emplace(uid, limParam); + }); + + } + else if (const NonTypeTemplateParmDecl* d = dyn_cast(param)) + limParam->setGenericParameterKind(d->isParameterPack() ? gpkNonTypePack : gpkNonType); + else if (const TemplateTemplateParmDecl* d = dyn_cast(param)) + limParam->setGenericParameterKind(d->isParameterPack() ? gpkTemplatePack : gpkTemplate); + else + limParam->setGenericParameterKind(GenericParameterKind::gpkType); + + return limParam; +} + +void ASTConverterVisitor::addFriendshipEdge(columbus::lim::asg::Class* limParent, columbus::NodeId friendId, const std::string& friendName) +{ + // Only add it once! + bool found = false; + if (friendId != 0) + { + for (auto it = limParent->getGrantsFriendshipListIteratorBegin(); it != limParent->getGrantsFriendshipListIteratorEnd(); ++it) + { + if (it->getFriend() && it->getFriend()->getId() == friendId) + { + found = true; + break; + } + } + } + + if (!found) + { + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + Friendship& fs = globalInfo.limFactory.createFriendship(friendId); + if (friendId == 0) + fs.setGrants(friendName); + + limParent->addGrantsFriendship(&fs); + }); + } +} + +void ASTConverterVisitor::createLIMType(const clang::Type* type) +{ + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + Factory& limFactory = globalInfo.limFactory; + MergeUIDFactory& uidFactory = conversionInfo.uidFactory; + auto& typeTable = globalInfo.typeTable; + + if (const BuiltinType* specificType = type->getAs()) + { + // TODO: Someone needs to review this, as many clang types are not covered in SimpleTypeKind! + SimpleTypeKind stk; + switch (specificType->getKind()) + { + case clang::BuiltinType::Void: stk = stkVoid; break; + case clang::BuiltinType::Bool: stk = stkBoolean; break; + case clang::BuiltinType::Char_U: stk = stkUnsignedCharacter; break; + case clang::BuiltinType::UChar: stk = stkUnsignedCharacter; break; + case clang::BuiltinType::WChar_U: stk = stkUnicode; break; // Sure? + case clang::BuiltinType::Char16: stk = stkUnicode; break; + case clang::BuiltinType::Char32: stk = stkUnicode; break; + case clang::BuiltinType::UShort: stk = stkUnsignedShort; break; + case clang::BuiltinType::UInt: stk = stkUnsignedInteger; break; + case clang::BuiltinType::ULong: stk = stkUnsignedLong; break; + case clang::BuiltinType::ULongLong: stk = stkUnsignedLong; break; + case clang::BuiltinType::Char_S: stk = stkCharacter; break; + case clang::BuiltinType::SChar: stk = stkCharacter; break; + case clang::BuiltinType::WChar_S: stk = stkUnicode; break; + case clang::BuiltinType::Short: stk = stkShort; break; + case clang::BuiltinType::Int: stk = stkInteger; break; + case clang::BuiltinType::Long: stk = stkLong; break; + case clang::BuiltinType::LongLong: stk = stkLong; break; + case clang::BuiltinType::Float: stk = stkFloat; break; + case clang::BuiltinType::Double: stk = stkDouble; break; + case clang::BuiltinType::LongDouble: stk = stkDouble; break; + case clang::BuiltinType::NullPtr: stk = stkUnknown; break; // Sure? + default: stk = stkUnknown; break; + } + + type::SimpleType& st = limFactory.createSimpleType(stk); + type::TypeFormerType& tf = limFactory.createTypeFormerType(st.getId()); + limFactory.addTypeFormer(tf.getId()); + } + else if (const ArrayType* specificType = type->getAsArrayTypeUnsafe()) + { + type::TypeFormer* tf; + tf = &limFactory.createTypeFormerArray(); + limFactory.addTypeFormer(tf->getId()); + + createLIMType(specificType->getElementType().getTypePtr()); + } + else if (type->isPointerType() || type->isReferenceType()) + { + type::TypeFormer& tf = limFactory.createTypeFormerPointer(type->isPointerType() ? PointerKind::ptkPointer : PointerKind::ptkReference); + limFactory.addTypeFormer(tf.getId()); + createLIMType(type->getPointeeType().getTypePtr()); + } + else if (const TemplateSpecializationType* specificType = type->getAs()) + { + // TemplateSpecializationType is not necessary a class template, + // as it can also be a template template parameter or alias template. + columbus::NodeId id = 0; + auto it = globalInfo.limTable.find(conversionInfo.uidFactory.createTypeId(QualType(specificType, 0), conversionInfo.pMyMangleContext)); + if (it != globalInfo.limTable.end()) + { + id = it->second->getId(); + } + else if (const CXXRecordDecl* ptr = specificType->getAsCXXRecordDecl()) + { + if (dyn_cast_or_null(ptr)) + { + //VisitCXXRecordDecl(ptr); + + Class *limClass = getOrCreateIncompleteNode_Class(ptr); + if(limClass) + id = limClass->getId(); + } + } + + // ID may not be setup (see the else case above) - in those cases we don't add the node. + if (id != 0) + { + type::TypeFormer& tf = limFactory.createTypeFormerType(id); + limFactory.addTypeFormer(tf.getId()); + } + } + else if (const RecordType* specificType = type->getAs()) + { + if (const CXXRecordDecl *cr = dyn_cast_or_null(specificType->getDecl())) + { + //specificType->dump(); + if (const CXXMethodDecl * md = cr->getLambdaCallOperator()) + { + //md->dump(); + createLIMType(md->getType().getTypePtr()); + return; + } + + columbus::lim::asg::base::Base *limClass = getOrCreateIncompleteNode_Class(cr); + if(limClass) + { + type::TypeFormer& tf = limFactory.createTypeFormerType(limClass->getId()); + limFactory.addTypeFormer(tf.getId()); + } + } + else + { + columbus::lim::asg::logical::Class *limClass = getOrCreateIncompleteNode(specificType->getDecl()); + if (limClass) + { + type::TypeFormer& tf = limFactory.createTypeFormerType(limClass->getId()); + limFactory.addTypeFormer(tf.getId()); + } + } + } + else if (const InjectedClassNameType* specificType = type->getAs()) + { + columbus::lim::asg::logical::Class *limClass = getOrCreateIncompleteNode_Class(specificType->getDecl()); + if (limClass) + { + type::TypeFormer& tf = limFactory.createTypeFormerType(limClass->getId()); + limFactory.addTypeFormer(tf.getId()); + } + } + else if (const TemplateTypeParmType* specificType = dyn_cast(type)) + { + if (const TemplateTypeParmDecl* decl = specificType->getDecl()) + { + //This is not eliminated... no reason + auto it = globalInfo.limTable.find(conversionInfo.uidFactory.create(decl, conversionInfo.pMyMangleContext)); + if (it != globalInfo.limTable.end()) + { + type::TypeFormer& tf = limFactory.createTypeFormerType(it->second->getId()); + limFactory.addTypeFormer(tf.getId()); + } + } + } + else if (type->isFunctionType()) + { + type::TypeFormer& tfp = limFactory.createTypeFormerPointer(PointerKind::ptkPointer); // need to store functions as function pointers (according to legacy) + limFactory.addTypeFormer(tfp.getId()); + + const FunctionType* specificType = type->castAs(); + ConvertType(specificType->getReturnType().getTypePtr()); + + limFactory.beginTypeFormerMethod(); + auto it = typeTable.find(uidFactory.createTypeId(QualType(specificType->getReturnType().getTypePtr(), 0), conversionInfo.pMyMangleContext)); + if (it != typeTable.end()) + { + base::Base* limRetType = it->second; + limFactory.setTypeFormerMethodHasReturnType(limRetType->getId()); + } + + if (type->isFunctionProtoType()) + { + const FunctionProtoType* specificType = type->castAs(); + for (auto pt : specificType->getParamTypes()) + { + ConvertType(pt.getTypePtr()); + auto it = typeTable.find(uidFactory.createTypeId(QualType(pt.getTypePtr(), 0), conversionInfo.pMyMangleContext)); + if (it != typeTable.end()) + { + base::Base* limParamType = it->second; + if (pt.getTypePtr()->isPointerType() || pt.getTypePtr()->isReferenceType()) + limFactory.addTypeFormerMethodHasParameterType(limParamType->getId(), ParameterKind::pmkInOut); + else + limFactory.addTypeFormerMethodHasParameterType(limParamType->getId(), ParameterKind::pmkIn); + } + } + } + + type::TypeFormerMethod& limMethodType = limFactory.endTypeFormerMethod(); + limFactory.addTypeFormer(limMethodType.getId()); + } + else if (const EnumType *et = dyn_cast_or_null(type)) + { + if (const EnumDecl *ed = et->getDecl()) + { + Class *limClass = getOrCreateIncompleteNode(ed); + if (limClass) + { + type::TypeFormer& tf = limFactory.createTypeFormerType(limClass->getId()); + limFactory.addTypeFormer(tf.getId()); + } + } + } + else + { + type::SimpleType& st = limFactory.createSimpleType(stkUnknown); + type::TypeFormerType& tf = limFactory.createTypeFormerType(st.getId()); + limFactory.addTypeFormer(tf.getId()); + } + /*else if (const AutoType *at = dyn_cast_or_null(type)) + { + if (at->isDeduced()) + { + at->dump(); + QualType dt = at->getDeducedType(); + if (!dt.isNull()) { + dt->dump(); + createLIMType(dt.getTypePtr()); + } + + return; + } + }*/ + }); +} + +const Decl* ASTConverterVisitor::getDeclFromStmt(const Stmt& stmt) +{ + auto parents = context.getParents(stmt); + + auto it = parents.begin(); + if (it == parents.end()) + return nullptr; + + const Decl* parentDecl = it->get(); + if (parentDecl) + return parentDecl; + + const Stmt* parentStmt = it->get(); + if (parentStmt) + { + if (const LambdaExpr *lambdaExpr = dyn_cast_or_null(parentStmt)) + return lambdaExpr->getCallOperator(); + else + return getDeclFromStmt(*parentStmt); + } + + return nullptr; +} + +const clang::DeclContext* ASTConverterVisitor::getFunctionContextFromStmt(const clang::Stmt& stmt) +{ + if (const Decl* d = getDeclFromStmt(stmt)) + { + if (FunctionDecl::classof(d)) + return cast(d); + + if (ObjCMethodDecl::classof(d)) + return cast(d); + + const DeclContext* dc = d->getParentFunctionOrMethod(); + if (dyn_cast_or_null(dc) || dyn_cast_or_null(dc)) + return dc; + } + + return nullptr; +} + +const clang::Decl* ASTConverterVisitor::getParentFromContext(const clang::Decl* decl) +{ + auto parents = context.getParents(*decl); + if (parents.empty()) + return nullptr; + + return parents.begin()->get(); +} + +void ASTConverterVisitor::handleAttributeAccess(const clang::ValueDecl* decl, const clang::FunctionDecl* func) +{ + //decl->dump(); + if (!decl || !func || decl->getAsFunction()) + return; + + if (isa(decl) && decl->getParentFunctionOrMethod()) + return; + + decl = getPrimaryTemplateVersionOfMemberDecl(decl); + //decl->dump(); + shared_ptr declUID = conversionInfo.uidFactory.create(decl, conversionInfo.pMyMangleContext); + Attribute *limAttribute = getOrCreateIncompleteNode(decl); + Method *limMethod = getOrCreateIncompleteNode_Method(func); + + if(limAttribute && limMethod) + { + // We need to check for access of global extern variables. These must be linked as the definition for the extern declaration is in a separate TU. + // Maybe sometimes this is also needed for fields? + if (const VarDecl *vd = dyn_cast(decl)) + { + if (!isDefinition(vd)) + { + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + globalInfo.linker.unresolved_attribute_accesses.push_back(std::pair, columbus::lim::asg::logical::Method*>(std::static_pointer_cast(declUID), limMethod)); + }); + return; + } + } + + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + AttributeAccess& access = globalInfo.limFactory.createAttributeAccess(limAttribute->getId()); + + if (!contains(limMethod->getAccessesAttributeListIteratorBegin(), limMethod->getAccessesAttributeListIteratorEnd(), &access)) + limMethod->addAccessesAttribute(&access); + }); + // We never use this imprint way, dunno if we should + //access.setAccesses(decl->getNameAsString()); + } +} + +/// Attempts to look up the original, non instantiated version of this declaration. +/// It only works with class members. They also must ha the base class NamedDecl +/// If the declaration is not templated to begin with, the function return it's parameter unchanged. +template +T ASTConverterVisitor::getPrimaryTemplateVersionOfMemberDecl(T input) { + const NamedDecl *decl = dyn_cast_or_null(input); + if(!decl) + return input; + + T ret = input; + if (const CXXRecordDecl *rec = dyn_cast_or_null(decl->getDeclContext())){ + if(const CXXRecordDecl *rec_pat = rec->getTemplateInstantiationPattern()){ + bool alreadyFoundOne = false; + + for (auto result : rec_pat->lookup(decl->getDeclName())){ + if (T casted = dynamic_cast(result)){ + if(alreadyFoundOne){ + //cout << "Failed manual lookup, ambiguous name " << decl->getNameAsString() << endl; + return input; + }else{ + alreadyFoundOne = true; + ret = casted; + } + } + } + } + } + return ret; +} + +columbus::lim::asg::SourcePosition ASTConverterVisitor::getSourcePosition(const clang::NamespaceDecl* decl) +{ + SourcePosition sp = getSourcePositionHelper(decl); + sp.setRealizationLevel(RealizationLevel::relDefines); + return sp; +} + +columbus::lim::asg::SourcePosition ASTConverterVisitor::getSourcePosition(const clang::CXXRecordDecl* decl) +{ + SourcePosition sp; + + if (const ClassTemplateDecl* templateDecl = decl->getDescribedClassTemplate()) + sp = getSourcePositionHelper(templateDecl); + else + sp = getSourcePositionHelper(decl); + + sp.setRealizationLevel(isDefinition(decl)?RealizationLevel::relDefines:RealizationLevel::relDeclares); + return sp; +} + +columbus::lim::asg::SourcePosition ASTConverterVisitor::getSourcePosition(const clang::FriendDecl* decl) +{ + SourcePosition sp = getSourcePositionHelper(decl); + sp.setRealizationLevel(RealizationLevel::relDeclares); + return sp; +} + +columbus::lim::asg::SourcePosition ASTConverterVisitor::getSourcePosition(const clang::TagDecl* decl) +{ + if(const CXXRecordDecl *crd = dyn_cast_or_null(decl)) //weird cast, because c and c++ style structs common + return getSourcePosition(crd); + + SourcePosition sp = getSourcePositionHelper(decl); + sp.setRealizationLevel(isDefinition(decl)?RealizationLevel::relDefines:RealizationLevel::relDeclares); + return sp; +} + +columbus::lim::asg::SourcePosition ASTConverterVisitor::getSourcePosition(const clang::FunctionDecl* decl) +{ + // Note: Deleted and defaulted functions are definitions (as they are ODR). + // Pure virtual functions can be declarations OR declarations and definitions (if there is an out-of-class definition for it). + SourcePosition sp; + const CXXRecordDecl *recordParent = dyn_cast_or_null(decl->getParent()); + + if (const FunctionTemplateDecl* templateDecl = decl->getDescribedFunctionTemplate()) + sp = getSourcePositionHelper(templateDecl); + else if(recordParent && recordParent->isLambda()) + sp = getSourcePositionHelper(recordParent->getBeginLoc(),decl->getEndLoc()); + else + sp = getSourcePositionHelper(decl); + + sp.setRealizationLevel(isDefinition(decl)?RealizationLevel::relDefines:RealizationLevel::relDeclares); + return sp; +} + +columbus::lim::asg::SourcePosition ASTConverterVisitor::getSourcePosition(const clang::ObjCMethodDecl* decl) +{ + SourcePosition sp = getSourcePositionHelper(decl); + sp.setRealizationLevel(isDefinition(decl)?RealizationLevel::relDefines:RealizationLevel::relDeclares); + return sp; +} + +columbus::lim::asg::SourcePosition ASTConverterVisitor::getSourcePosition(const clang::FieldDecl* decl) +{ + SourcePosition sp = getSourcePositionHelper(decl->getBeginLoc(), decl->getLocation()); + sp.setRealizationLevel(RealizationLevel::relDefines); + return sp; +} + +columbus::lim::asg::SourcePosition ASTConverterVisitor::getSourcePosition(const clang::VarDecl* decl) +{ + SourcePosition sp = getSourcePositionHelper(decl->getBeginLoc(), decl->getLocation()); + sp.setRealizationLevel(isDefinition(decl)?RealizationLevel::relDefines:RealizationLevel::relDeclares); + return sp; +} + +columbus::lim::asg::SourcePosition ASTConverterVisitor::getSourcePosition(const clang::EnumConstantDecl* decl) +{ + SourcePosition sp = getSourcePositionHelper(decl); + sp.setRealizationLevel(RealizationLevel::relDefines); + return sp; +} + +columbus::lim::asg::SourcePosition ASTConverterVisitor::getSourcePosition(const clang::ObjCInterfaceDecl* decl) +{ + SourcePosition sp = getSourcePositionHelper(decl); + sp.setRealizationLevel(isDefinition(decl)?RealizationLevel::relDefines:RealizationLevel::relDeclares); + return sp; +} + +columbus::lim::asg::SourcePosition ASTConverterVisitor::getSourcePosition(const clang::ObjCCategoryDecl* decl) +{ + SourcePosition sp = getSourcePositionHelper(decl); + sp.setRealizationLevel(RealizationLevel::relDefines); + return sp; +} + +columbus::lim::asg::SourcePosition ASTConverterVisitor::getSourcePosition(const clang::ObjCProtocolDecl* decl) +{ + SourcePosition sp = getSourcePositionHelper(decl); + sp.setRealizationLevel(isDefinition(decl)?RealizationLevel::relDefines:RealizationLevel::relDeclares); + return sp; +} + +SourcePosition ASTConverterVisitor::getSourcePositionHelper(const Decl* decl) +{ + return getSourcePositionHelper(decl->getBeginLoc(), decl->getEndLoc()); +} + +SourcePosition ASTConverterVisitor::getSourcePositionHelper(SourceLocation start, SourceLocation end) +{ + const SourceManager& sm = context.getSourceManager(); + /*start.dump(sm); + cout << endl; + + end.dump(sm); + cout << endl;*/ + + SourcePosition ret; + + // for macros, we would like to set these lines and columns to the place where they are expanded (instead of the macro location) + // (this is the way it was done on the former one (EDG) too) + if (start.isMacroID() || end.isMacroID()) + { + ret.setLine(sm.getExpansionLineNumber(start)); + ret.setColumn(sm.getExpansionColumnNumber(start)); + ret.setEndLine(sm.getExpansionLineNumber(end)); + ret.setEndColumn(sm.getExpansionColumnNumber(end)); + } + else + { + end = Lexer::getLocForEndOfToken(end, 1, sm, context.getLangOpts()); + ret.setLine(sm.getSpellingLineNumber(start)); + ret.setColumn(sm.getSpellingColumnNumber(start)); + ret.setEndLine(sm.getSpellingLineNumber(end)); + ret.setEndColumn(sm.getSpellingColumnNumber(end)); + } + + return ret; +} + +template<> columbus::lim::asg::Attribute* ASTConverterVisitor::createNodeHelper() +{ + return conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + return globalInfo.limFactory.createAttributeNode(); + }); +} + +template<> columbus::lim::asg::Package* ASTConverterVisitor::createNodeHelper() +{ + return conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + return globalInfo.limFactory.createPackageNode(); + }); +} + +template<> columbus::lim::asg::Class* ASTConverterVisitor::createNodeHelper() +{ + return conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + return globalInfo.limFactory.createClassNode(); + }); +} + +template<> columbus::lim::asg::Method* ASTConverterVisitor::createNodeHelper() +{ + return conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + return globalInfo.limFactory.createMethodNode(); + }); +} + +template<> columbus::lim::asg::MethodGeneric* ASTConverterVisitor::createNodeHelper() +{ + return conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + return globalInfo.limFactory.createMethodGenericNode(); + }); +} + +template<> columbus::lim::asg::MethodGenericSpec* ASTConverterVisitor::createNodeHelper() +{ + return conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + return globalInfo.limFactory.createMethodGenericSpecNode(); + }); +} + +template<> columbus::lim::asg::ClassGeneric* ASTConverterVisitor::createNodeHelper() +{ + return conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + return globalInfo.limFactory.createClassGenericNode(); + }); +} + +template<> columbus::lim::asg::ClassGenericSpec* ASTConverterVisitor::createNodeHelper() +{ + return conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + return globalInfo.limFactory.createClassGenericSpecNode(); + }); +} + +void ASTConverterVisitor::addMemberEdge(const clang::Decl* parent, columbus::lim::asg::logical::Member* to) +{ + if (!parent || !to) { + WriteMsg::write(WriteMsg::mlDebug, "addMemberEdge ERROR: parent is null\n"); + return; + } + + // This is a rare case where the "extern "C"" linkage declaration surrounds the actual declaration + // This could be around a function or global var ; this is always in some namespace scope and it might be nested + // So we just step through it and call recursively + if (const LinkageSpecDecl *lsd = dyn_cast_or_null(parent)) + { + addMemberEdge(dyn_cast(lsd->getParent()),to); + } + else if (parent && (isa(parent) || isa(parent) || isa(parent) || isa(parent) + || isa(parent) || isa(parent) || isa(parent) || isa(parent))) + { + Scope *limParent = getOrCreateIncompleteNode_Scope(parent); + if(limParent) + { + // Add it only once. + for (auto mit = limParent->getMemberListIteratorBegin(); mit != limParent->getMemberListIteratorEnd(); ++mit) + { + if (mit->getId() == to->getId()) + return; + } + + limParent->addMember(to); + return; + } + } + else if (isa(parent)) + { + // Add it only once. + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + for (auto mit = globalInfo.limFactory.getRoot()->getMemberListIteratorBegin(); + mit != globalInfo.limFactory.getRoot()->getMemberListIteratorEnd(); + ++mit) + { + if (mit->getId() == to->getId()) + return; + } + globalInfo.limFactory.getRoot()->addMember(to); + }); + } + else + { + WriteMsg::write(WriteMsg::mlDebug, "addMemberEdge ERROR: parent is not a handled type\n"); + } +} + +void ASTConverterVisitor::addUsesEdgeForStmt(columbus::lim::asg::logical::Member* to, const clang::Stmt* stmt, bool recursive) +{ + // Safety. + if (!to || !stmt) + return; + + // Add result types. + // Note: Not all cases are handled in the switch, because most of them only contain sub-expressions + // on which we can just iterate over with Stmt::children(). Non-standard extensions are also ignored. + // TODO: Not yet tested and some cases are known to be missing the addition of type info. + switch (stmt->getStmtClass()) + { + case clang::Stmt::CXXBoolLiteralExprClass: + addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + break; + case clang::Stmt::CXXNoexceptExprClass: + addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + break; + case clang::Stmt::CXXNullPtrLiteralExprClass: + addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + break; + case clang::Stmt::CXXThisExprClass: + { + const CXXThisExpr* e = cast(stmt); + //if (!e->isImplicit()) //ez menjen implicitbe is! + addUsesEdgeForType(to, e->getType().getTypePtr()); + } + break; + case clang::Stmt::CXXTypeidExprClass: + addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + break; + case clang::Stmt::CallExprClass: + addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + break; + case clang::Stmt::CXXMemberCallExprClass: + addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + break; + case clang::Stmt::CXXOperatorCallExprClass: + addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + break; + case clang::Stmt::UserDefinedLiteralClass: + addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + break; + case clang::Stmt::CStyleCastExprClass: + addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + break; + case clang::Stmt::CXXFunctionalCastExprClass: + addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + break; + case clang::Stmt::CXXConstCastExprClass: + addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + break; + case clang::Stmt::CXXDynamicCastExprClass: + addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + break; + case clang::Stmt::CXXReinterpretCastExprClass: + addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + break; + case clang::Stmt::CXXStaticCastExprClass: + addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + break; + case clang::Stmt::CharacterLiteralClass: + addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + break; + case clang::Stmt::CompoundLiteralExprClass: + addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + break; + case clang::Stmt::DeclRefExprClass: + addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + break; + case clang::Stmt::FloatingLiteralClass: + addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + break; + case clang::Stmt::IntegerLiteralClass: + addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + break; + case clang::Stmt::LambdaExprClass: + addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + return; // dont traverse into lambdas ever + break; + case clang::Stmt::MemberExprClass: + { + const Type* t = cast(stmt)->getType().getTypePtr(); + if (t != nullptr && !t->isPlaceholderType()) + addUsesEdgeForType(to, t); + break; + } + case clang::Stmt::SizeOfPackExprClass: + addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + break; + case clang::Stmt::StringLiteralClass: + addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + break; + case clang::Stmt::UnaryExprOrTypeTraitExprClass: + { + const UnaryExprOrTypeTraitExpr* expr = cast(stmt); + if (expr->isArgumentType()) + addUsesEdgeForType(to, expr->getArgumentType().getTypePtr()); + else + addUsesEdgeForStmt(to, cast(stmt)->getArgumentExpr()); + } + break; + case clang::Stmt::CXXConstructExprClass: + addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + break; + default: + //addUsesEdgeForType(to, cast(stmt)->getType().getTypePtr()); + break; + } + + // Recursively visit sub-expressions. + if(recursive) + for (const Stmt* c : stmt->children()) + addUsesEdgeForStmt(to, c); +} + +void ASTConverterVisitor::addUsesEdgeForType(columbus::lim::asg::logical::Member* to, const clang::Type* type) +{ + //type->dump(); + //cout << conversionInfo.uidFactory.createTypeId(QualType(type, 0)) << endl; + ConvertType(type); + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + auto it = globalInfo.typeTable.find(conversionInfo.uidFactory.createTypeId(QualType(type, 0), conversionInfo.pMyMangleContext)); + if (it != globalInfo.typeTable.end()) + { + //cout << it->second->getId() << endl; + bool found = false; + // Ensure that it's not added + for (auto it2 = to->getUsesListIteratorBegin(); it2 != to->getUsesListIteratorEnd(); ++it2) + { + if (it2->getId() == it->second->getId()) + { + found = true; + break; + } + } + + if (Method* m = dynamic_cast(to)) + { + // Ensure that it's not added already as instantiation + for (auto mit = m->getInstantiatesListIteratorBegin(); mit != m->getInstantiatesListIteratorEnd(); ++mit) + { + if (mit->getId() == it->second->getId()) + { + found = true; + break; + } + } + // Ensure that it's not added already as return value + for (auto mit = m->getReturnsListIteratorBegin(); mit != m->getReturnsListIteratorEnd(); ++mit) + { + if (mit->getId() == it->second->getId()) + { + found = true; + break; + } + } + // Ensure that it's not added already as parameter + for (auto mit = m->getParameterListIteratorBegin(); mit != m->getParameterListIteratorEnd(); ++mit) + { + if (mit->getType() && mit->getType()->getId() == it->second->getId()) + { + found = true; + break; + } + } + } + else if(Attribute* a = dynamic_cast(to)) + { + // Ensure that it's not added already as hasType + for (auto ait = a->getTypeListIteratorBegin(); ait != a->getTypeListIteratorEnd(); ++ait) + { + if (ait->getId() == it->second->getId()) + { + found = true; + break; + } + } + } + if (!found) + { + to->addUses(it->second); + } + } + }); +} + +bool ASTConverterVisitor::addInstantiatesEdge(const clang::FunctionDecl* f, const clang::Type* type) +{ + Method *m = getOrCreateIncompleteNode_Method(f); + if(!m) + return false; + + ConvertType(type); + columbus::lim::asg::type::Type* t = nullptr; + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + auto rit = globalInfo.typeTable.find(conversionInfo.uidFactory.createTypeId(QualType(type, 0), conversionInfo.pMyMangleContext)); + if (!(rit == globalInfo.typeTable.end())) + t = rit->second; + }); + + if (!t) + return false; + + // Ensure that it's not added already. + for (auto it = m->getInstantiatesListIteratorBegin(); it != m->getInstantiatesListIteratorEnd(); ++it) + { + if (it->getId() == t->getId()) + return false; + } + + // If it's added as a 'uses' edge, remove the uses edge. + for (auto it = m->getUsesListIteratorBegin(); it != m->getUsesListIteratorEnd(); ++it) + { + if (it->getId() == t->getId()) + { + m->removeUses(it->getId()); + break; + } + } + + m->addInstantiates(t); + return true; +} + +template +void ASTConverterVisitor::addTemplateArgumentEdge(const clang::TemplateArgument& arg, T* limTo) +{ + // Type that needs to be added as argument. + const Type* type; + switch (arg.getKind()) + { + case TemplateArgument::Type: + type = arg.getAsType().getTypePtr(); + break; + + case TemplateArgument::Declaration: + type = arg.getAsDecl()->getType().getTypePtr(); + break; + + case TemplateArgument::NullPtr: + type = arg.getNullPtrType().getTypePtr(); + break; + + case TemplateArgument::Integral: + type = arg.getIntegralType().getTypePtr(); + break; + + case TemplateArgument::Template: + { + const TemplateDecl* d = arg.getAsTemplate().getAsTemplateDecl(); + if (d) + { + if (const TypeDecl* td = dyn_cast_or_null(d->getTemplatedDecl())) + type = td->getTypeForDecl(); + else + type = nullptr; + } + else + { + type = nullptr; + } + } + break; + + case TemplateArgument::TemplateExpansion: + /* TODO */ + type = nullptr; + break; + + case TemplateArgument::Expression: + /* TODO */ + type = nullptr; + break; + + case TemplateArgument::Pack: + for (const TemplateArgument& a : arg.pack_elements()) + addTemplateArgumentEdge(a, limTo); + return; + + default: + type = nullptr; + break; + } + + if (type) + { + ConvertType(type); + conversionInfo.globalInfo.call([&](GlobalASTConversionInfo& globalInfo) { + auto it = globalInfo.typeTable.find(conversionInfo.uidFactory.createTypeId(QualType(type, 0), conversionInfo.pMyMangleContext)); + if (it != (globalInfo.typeTable.end())) + limTo->addArguments(it->second, tackNone); + }); + } +} + +Convert2LimAction::Convert2LimAction(ASTConversionInfo& conversionInfo) + : conversionInfo(conversionInfo) +{} + +unique_ptr Convert2LimAction::CreateASTConsumer(CompilerInstance& compiler, StringRef inFile) +{ + conversionInfo.pMyMangleContext.reset(clang::ItaniumMangleContext::create(compiler.getASTContext(), compiler.getDiagnostics())); + return unique_ptr(new ASTConverterConsumer(conversionInfo)); +} + +unique_ptr newConvert2LimActionFactory(ASTConversionInfo& conversionInfo) +{ + class SimpleFrontendActionFactory : public FrontendActionFactory { + public: + SimpleFrontendActionFactory(ASTConversionInfo& conversionInfo) : conversionInfo(conversionInfo) {} + unique_ptr create() override { return unique_ptr(new Convert2LimAction(conversionInfo)); } + private: + ASTConversionInfo& conversionInfo; + }; + + return unique_ptr(new SimpleFrontendActionFactory(conversionInfo)); +} + + diff --git a/cl/CAN2Lim/src/CommentProcessor.cpp b/cl/CAN2Lim/src/CommentProcessor.cpp new file mode 100644 index 0000000..7abbe27 --- /dev/null +++ b/cl/CAN2Lim/src/CommentProcessor.cpp @@ -0,0 +1,280 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "../inc/CommentProcessor.h" +#include "../inc/ASTConversionInfo.h" + +#include +#include + +#include + +extern std::string g_filterfile; +using namespace std; +using namespace common; + +CommentProcessor::CommentProcessor(GlobalASTConversionInfo& conversionInfo) : conversionInfo(conversionInfo) +{ +} + +void CommentProcessor::loadCommentStructure(const std::string& astFile) +{ + DirectoryFilter directoryFilter; + directoryFilter.openFilterFile(g_filterfile); + std::string renamedASTFile = cANFilePathRenamer.changeToLIMCompatible(common::pathCanonicalize(astFile)); + std::ifstream file(renamedASTFile + ".comment"); + + unsigned prevCommentLineEnd = 0; + columbus::lim::asg::physical::File *limFile = nullptr; + if (!file.good()) + { + WriteMsg::write(WriteMsg::mlDebug, "FILE ERROR: .comment file with name (%s) is missing\n", (renamedASTFile + ".comment").c_str()); + } + while (file.good()) + { + char entryMarker; + file >> entryMarker; + if (entryMarker == 1) // We encountered a new file + { + std::string fileName; + file >> std::quoted(fileName) >> std::ws; + if(fileName.c_str() && conversionInfo.changePathFrom.c_str() && conversionInfo.changePathTo.c_str()) + fileName = common::replace(fileName.c_str(), conversionInfo.changePathFrom.c_str(), conversionInfo.changePathTo.c_str()); + + // This is doing a replace a second time (it was already done once in CAN). It's required because of the flaws of our testing system. + if (fileName.c_str() && conversionInfo.changePathFrom.c_str() && conversionInfo.changePathTo.c_str()) + fileName = common::replace(fileName.c_str(), conversionInfo.changePathFrom.c_str(), conversionInfo.changePathTo.c_str()); + + + prevCommentLineEnd = 0; // needed for overlaps + + limFile = nullptr; + auto findIt = conversionInfo.correctedFileNameToFileNode.find(fileName); + if (findIt != conversionInfo.correctedFileNameToFileNode.end() && findIt->second != nullptr) + { + limFile = findIt->second; + } + + if (!limFile) + { + WriteMsg::write(WriteMsg::mlDebug, "file error while reading comments : lim filenode with filename(%s) is not found!\n", fileName.c_str()); + continue; + } + } + else //we encountered a comment + { + CommentData data; + string text; + file >> data.begin.line >> data.begin.column >> data.end.line >> data.end.column >> std::quoted(text) >> std::ws; + + if (!limFile || text.empty()) { + continue; + } + + data.text = text; + + auto insertionResult = commentTablePerFile[limFile].insert(data); + if (insertionResult.second) + { + unsigned CLOCToAdd = (data.end.line - data.begin.line) + 1; + if (prevCommentLineEnd == data.begin.line) //if 2 comments are on the same line, there needs to be a -1 penalty (as it's 2 comments, but only 1 commentLine) + { + CLOCToAdd--; + } + limFile->setCLOC(limFile->getCLOC() + CLOCToAdd); + + prevCommentLineEnd = data.end.line; + } + } + //if(conversionInfo.filesAlreadyProcessed.count(filename) == 0) + // std::cout << "Throwing away comment" << std::endl; + } +} + +void CommentProcessor::addDocumentationToMember(columbus::lim::asg::logical::Member* member, const CommentData& comment, bool postAdd = false) +{ + if (!postAdd) + docCache.push_back(std::make_pair(member, comment)); + else + { + member->addComment(&conversionInfo.limFactory.createComment(comment.text)); + } + +} + +void CommentProcessor::addCommentToMember(columbus::lim::asg::logical::Member* member, const CommentData &comment, const CommentData *prevComment) +{ + unsigned toAdd = comment.numberOfLines(); + + /*common::WriteMsg::write(common::WriteMsg::mlNormal, "DAVID: This comment endline: %d\n", comment.end.line); + if (prevComment) + common::WriteMsg::write(common::WriteMsg::mlNormal, "DAVID: prev comment beginline: %d\n", prevComment->begin.line);*/ + + // required for Case: /*comment1*/ /*comment2*/ + // as these as 2 comments, but only 1 commentline + if (prevComment && prevComment->overlaps(comment)) + { + toAdd--; + } + member->setCommentLines(member->getCommentLines() + toAdd); +} + +/* + Based on the commentsTable collected from the .comment file earlier and the now almost complete lim tree, we must now + decide which comments belongs to which Member/scope. + Comments before Members (such as classes or functions) are documentation comments and they must be inserted + with a hasComment edge to that Member. + The regular comments are simply added to the scopes commentLines attribute. + The algorithm simplified: + Traverses the commentTable and the scopeList (vector of scope beginnings and endings) from BOTTOM UPWARDS! + Meanwhile, a stack of scopes is being built, so that we track which scopes are we in. + For each comment, we iterate upwards the scopes, so that at each point, we have the relevant information. + At the end, the added documentation comments need to be reversed (to adhere with the rule, that comment edges are ordered by id) + By the way, the reason the iteration is bottom-up (and not top-down), is that this way it is easier to deal with chains (comments on consecutive lines) +*/ +void CommentProcessor::bindCommentsToLimTree(columbus::lim::asg::physical::File *file) { + std::set &commentTable = commentTablePerFile[file]; + std::vector &scopeList = conversionInfo.scopeListPerFile[file]; + conversionInfo.addGlobalNamespaceToScopeList(scopeList); + + std::sort(scopeList.begin(), scopeList.end()); + + /*for (ScopeGuard sg : scopeList) { //DEBUG + common::WriteMsg::write(common::WriteMsg::mlNormal, "DAVID: ScopeGuard name = %s, type = %s, line = %d, column = %d\n", + sg.scope.member->getName().c_str(), + (sg.guardType == ScopeGuard::BEGIN ? "BEGIN" : "END"), + sg.getSourcePoint().line, + sg.getSourcePoint().column + ); + }*/ + + docCache.clear(); + std::stack scopeStack; + auto scopeGuard = scopeList.rbegin(); + scopeStack.push(scopeGuard->scope); //itt majd pointerekkel kéne + bool chaining = false; + const CommentData *prevComment = nullptr; + + for (auto comment = commentTable.rbegin(); comment != commentTable.rend(); ++comment) + { + //step the scopeGuards upwards until it reaches the comment + while (scopeGuard != prev(scopeList.rend()) && comment->begin < next(scopeGuard)->getSourcePoint()) + { + ++scopeGuard; + if (scopeStack.top() == scopeGuard->scope) + scopeStack.pop(); + else + scopeStack.push(scopeGuard->scope); + chaining = false; // scopechange breaks chaining + prevComment = nullptr; // scopechange breaks comment line duplications + } + + // Case: class B{}; /* comment */ class C{}; + // The comment should belong to C as documentation + if (scopeGuard->guardType == ScopeGuard::BEGIN + && scopeGuard->getSourcePoint().line == comment->end.line) + { + addDocumentationToMember(scopeGuard->scope.member, *comment); + } + // Case: //comment line above member + // class B{ + // This comment should belong to B as documentation; Also this might be the beginning of a documentation comment-chain + else if (scopeGuard->guardType == ScopeGuard::BEGIN + && scopeGuard->getSourcePoint().line == comment->end.line + 1 + && next(scopeGuard)->scope.begin.line + 1 != scopeGuard->getSourcePoint().line) + { + addDocumentationToMember(scopeGuard->scope.member, *comment); + chaining = true; + } + // Case: class C{ //doc comment + // This comment belongs to C as documentation. + else if (next(scopeGuard)->guardType == ScopeGuard::BEGIN + && next(scopeGuard)->getSourcePoint().line == comment->begin.line) + { + addDocumentationToMember(next(scopeGuard)->scope.member, *comment); + } + // Case: int x, k; //doc comment + // This comment belongs to k as documentation + else if (next(scopeGuard)->guardType == ScopeGuard::END + && next(scopeGuard)->scope.begin.line == comment->begin.line) + { + addDocumentationToMember(next(scopeGuard)->scope.member, *comment); + } + // Case: // 1 the comment we inspect + // // 2 blablablabla + // class B{ + // Comment 1 belongs to B as documentation, as it's is chained to comment 2 + else if (chaining && prev(comment)->begin.line <= comment->end.line + 1) + { + addDocumentationToMember(scopeGuard->scope.member, *comment); + } + // Case: class A{ + // //comment + // This comment belongs to A as regular comment + else if (next(scopeGuard)->guardType == ScopeGuard::BEGIN) + { + chaining = false; + addCommentToMember(next(scopeGuard)->scope.member, *comment, prevComment); + prevComment = &(*comment); + } + // Case: class A{ + // class B{ + // } + // //comment + // } + // This comment belongs to A as regular comment + else if (next(scopeGuard)->guardType == ScopeGuard::END) + { + chaining = false; + addCommentToMember(scopeStack.top().member, *comment, prevComment); + prevComment = &(*comment); + } + else + { + //common::WriteMsg::write(common::WriteMsg::mlNormal, "DAVID: Impossible comment case\n"); + } + } + + // we need to apply the edges in an increasing id order, so we reverse the cache, and add them + // also, we we concatenate multiline doc comments + std::string chain; + for (auto it = docCache.rbegin(); it != docCache.rend(); ++it) + { + if ( it != prev(docCache.rend()) + && it->first == next(it)->first + && (it->second.begin.column == next(it)->second.begin.column + || it->second.begin.line == next(it)->second.end.line)) + { + chain += it->second.text; + if(!(it->second.begin.line == next(it)->second.end.line)) + chain += char(10); + } + else + { + if (!chain.empty()) + { + chain += it->second.text; + it->second.text = chain; + chain = ""; + } + addDocumentationToMember(it->first, it->second, true); + } + } +} diff --git a/cl/CAN2Lim/src/Linker.cpp b/cl/CAN2Lim/src/Linker.cpp new file mode 100644 index 0000000..db66791 --- /dev/null +++ b/cl/CAN2Lim/src/Linker.cpp @@ -0,0 +1,244 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "../inc/Linker.h" +#include "../inc/clangHelpers.h" +#include "../inc/ASTConversionInfo.h" + +#include + + +using namespace std; +using namespace clang; +using namespace columbus::lim::asg; + +void Linker::add_definition(Member * limNode, std::shared_ptr uid) +{ + UID_to_definitions.emplace(std::static_pointer_cast(uid), limNode); +} + +void Linker::add_declaration(Member * limNode, std::shared_ptr uid) +{ + unresolved_declarations.push_back(std::pair,columbus::lim::asg::Member*>(std::static_pointer_cast(uid), limNode)); +} + +/*void Linker::handle_decl(const Decl * decl, std::shared_ptr uid, Member * limNode) +{ + if (isDefinition(decl)) + { + UID_to_definitions.emplace(std::static_pointer_cast(uid), limNode); + } + else + { + if(const Decl* localDefinition = getLocalDefinition(decl)) + { + //cout << "LINKER: Local defintion found for declaration: " << limNode->getName() << endl; + std::shared_ptr localDefinitionUID = conversionInfo.uidFactory.create(localDefinition); + auto localDefinitionIt = conversionInfo.limTable.find(localDefinitionUID); + if (localDefinitionIt != conversionInfo.limTable.end()) + { + //cout << "LINKER: Local defintion linked to declaration!" << endl; + limNode->setDeclares(dynamic_cast(localDefinitionIt->second)); + } + else + { + conversionInfo.linker.unresolved_declarations.push_back(std::pair,columbus::lim::asg::Member*>(std::static_pointer_cast(uid), limNode)); + } + } + else + { + conversionInfo.linker.unresolved_declarations.push_back(std::pair,columbus::lim::asg::Member*>(std::static_pointer_cast(uid), limNode)); + } + } +}*/ + +bool Linker::link_unresolved_declarations() +{ + if(LINKER_DEBUG) + print_debug_overview(); + + for (auto decl_kv : unresolved_declarations) + { + bool foundDefinitionForDeclaration = false; + if(UID_to_definitions.count(decl_kv.first) == 0) + { + //if there is no definition for the declaration UID then we have to go no further, just skip this and go for next + if(LINKER_DEBUG) + cout << "Definition not found for " << decl_kv.first->getMangledName() << endl; + continue; + } + + //check for each component (Note: we are using belongsTo edges of file nodes, so they must be set already) + for (auto decl_comp_it = decl_kv.second->getBelongsToListIteratorBegin(); decl_comp_it != decl_kv.second->getBelongsToListIteratorEnd(); ++decl_comp_it) + { + if(SIMPLIFIED_LINKING && foundDefinitionForDeclaration) //in this case, we don't handle component-specific linking, so just break after finding the first definition + break; + + const columbus::lim::asg::base::Component *decl_component = &(*decl_comp_it); + auto range = UID_to_definitions.equal_range(decl_kv.first); + for (auto def_it = range.first; def_it != range.second; ++def_it) + { + if(def_it->second->getIsContainedInIsEmpty()) + break; //definitions must have a containedIn file + + const columbus::lim::asg::physical::File *file = &(*(def_it->second->getIsContainedInListIteratorAssocBegin())); + if (component_to_files[const_cast(decl_component)].count(const_cast(file)) == 1) + { + //the declaration and the definition is in the same component, so link them! + //The only problem here is that the LIM is incapable of handling component-dependent linking, so here we just overwrite if there are multiple definitions... + decl_kv.second->setDeclares(def_it->second); //TODO: modify this line accordingly, if the LIM schema is ready for it (and turn off SIMPLIFIED_LINKING) + foundDefinitionForDeclaration = true; + if(LINKER_DEBUG) + cout << "Linked declaration " << decl_kv.first->getMangledName() << " in component " << decl_component->getName() << " to definition "<< def_it->first->getMangledName() <<" in file " << file->getName() << endl; + break; //a declaration can only be linked to one file per component(if there are no multiple definitions, in which case, it shouldn't even build...) + } + } + } + if(LINKER_DEBUG && !foundDefinitionForDeclaration) + //in this case there IS a definition for the declaration just not in the same compononent so we cannot link them + cout << "Definition not found for " << decl_kv.first->getMangledName() << endl; + } + + return true; +} + +bool Linker::link_unresolved_calls() +{ + //helper lambda + auto hasCallsAlready = [](auto node, columbus::NodeId callId) + { + for (auto it = node->getCallsListIteratorBegin(); it != node->getCallsListIteratorEnd(); ++it) + { + if (it->getId() == callId) + return true; + } + + return false; + }; + + for (auto call_kv : unresolved_calls) + { + bool foundDefinitionForCall = false; + if(UID_to_definitions.count(call_kv.first) == 0) + { + //if there is no definition for the call UID then we have to go no further, just skip this and go for next + if(LINKER_DEBUG) + cout << "Definition not found for " << call_kv.first->getMangledName() << endl; + continue; + } + + auto range = UID_to_definitions.equal_range(call_kv.first); + for (auto def_it = range.first; def_it != range.second; ++def_it) + { + // This is defense against a bug that i couldnt handle properly + // If its not a method dont try to put a call on it + if (dynamic_cast(def_it->second) == NULL) + continue; + + MethodCall *limCall = &conversionInfo.limFactory.createMethodCall(def_it->second->getId()); + if (Attribute *attr = dynamic_cast(call_kv.second)) + { + //cout << attr->getName() << endl; + if(!hasCallsAlready(attr,limCall->getId())) + attr->addCalls(limCall); + } + else if (Method *method = dynamic_cast(call_kv.second)) + { + if(!hasCallsAlready(method,limCall->getId())) + method->addCalls(limCall); + } + } + + if(LINKER_DEBUG && !foundDefinitionForCall) + cout << "Definition not found for " << call_kv.first->getMangledName() << endl; + + } + return true; +} + +bool Linker::link_unresolved_attribute_accesses() +{ + for (auto access_kv : unresolved_attribute_accesses) + { + bool foundDefinitionForCall = false; + if(UID_to_definitions.count(access_kv.first) == 0) + { + //if there is no definition for the call UID then we have to go no further, just skip this and go for next + if(LINKER_DEBUG) + cout << "Definition not found for " << access_kv.first->getMangledName() << endl; + continue; + } + + auto range = UID_to_definitions.equal_range(access_kv.first); + for (auto def_it = range.first; def_it != range.second; ++def_it) + { + if (Attribute* limAttribute = dynamic_cast(def_it->second)) + { + AttributeAccess& access = conversionInfo.limFactory.createAttributeAccess(limAttribute->getId()); + Method* limMethod = access_kv.second; + + if(!contains(limMethod->getAccessesAttributeListIteratorBegin(),limMethod->getAccessesAttributeListIteratorEnd(),&access)) + limMethod->addAccessesAttribute(&access); + } + + } + + if(LINKER_DEBUG && !foundDefinitionForCall) + cout << "Definition not found for " << access_kv.first->getMangledName() << endl; + + } + return true; +} + +void Linker::print_debug_overview() +{ + if (LINKER_DEBUG) + { + cout << "Linking overview:" << endl; + /*cout << "File to components map:" << endl; + for (auto kv : file_to_components) + { + cout << "File: " << kv.first->getName() << " , it's components: " << endl; + for(auto component : kv.second) + { + cout << component->getName() << endl; + } + }*/ + cout << "Component to files map:" << endl; + for (auto kv : component_to_files) + { + cout << "Component: " << kv.first->getName() << " , it's files: " << endl; + for(auto file : kv.second) + { + cout << file->getName() << endl; + } + } + cout << "Unresolved declarations:" << endl; + for (auto p : unresolved_declarations) + { + cout << "UID: " << p.first->getMangledName() << " , declarationName: " << p.second->getName() << endl; + } + cout << "Definitions:" << endl; + for (auto p : UID_to_definitions) + { + cout << "UID: " << p.first->getMangledName() << " , definitionName: " << p.second->getName() << endl; + } + } +} diff --git a/cl/CAN2Lim/src/MergeUID.cpp b/cl/CAN2Lim/src/MergeUID.cpp new file mode 100644 index 0000000..b33323e --- /dev/null +++ b/cl/CAN2Lim/src/MergeUID.cpp @@ -0,0 +1,450 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + + +#include "../inc/MergeUID.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; +using namespace clang; + +boost::mutex MergeUID::m; +extern CANFilePathRenamer cANFilePathRenamer; + +MergeUID::MergeUID(const string& mangledName, std::string fileName, unsigned lineNumber, unsigned columnNumber, bool isNamespace) + : mangledName (mangledName) + , fileName(common::pathCanonicalize(fileName)) + , lineNumber(lineNumber) + , columnNumber(columnNumber) + , hashValue (std::hash()(mangledName /*+ (isNamespace ? "" : "|" + common::pathCanonicalize(fileName))*/)) + , isNamespace(isNamespace) +{ + // TODO: More sophisticated solution to combine hash values. +} + +bool MergeUID::equals(const metrics::UID& rhs) const +{ + assert(typeid(rhs) == typeid(MergeUID) && "Invalid UID type!"); + const MergeUID& other = static_cast(rhs); + + // For namespaces, only the mangled name counts. + if (isNamespace) + return mangledName == other.mangledName; + + // Allow 0 line numbers to always compare equal so we can safely compare Decl IDs with Type IDs. + return mangledName == other.mangledName && + (!lineNumber || !other.lineNumber || lineNumber == other.lineNumber) && + (!columnNumber || !other.columnNumber || columnNumber == other.columnNumber) && + fileName == other.fileName; +} + +size_t MergeUID::hash() const +{ + return hashValue; +} + +void MergeUIDFactory::declContextName(SourceManager& sm, llvm::raw_string_ostream& ss, const DeclContext* parent) +{ + // For non-functions the qualified name identifies the object - only need to take care of cases where decl + // is within an anonymous namespace or class. + // Iterate through the AST hierarchy to check if there's an anonymous parent. + while (parent) + { + if (NamespaceDecl::classofKind(parent->getDeclKind())) + { + const NamespaceDecl* ns = static_cast(parent); + if (ns->isAnonymousNamespace()) + { + // Put the filepath into the stream, prefixed by a "//" and break. + ss << "//" << cANFilePathRenamer.changeToLIMCompatible(common::pathCanonicalize(sm.getFilename(ns->getLocation()).str())); + break; + } + } + else if (CXXRecordDecl::classofKind(parent->getDeclKind())) + { + const CXXRecordDecl* cs = static_cast(parent); + if (cs->isAnonymousStructOrUnion() || cs->getName().empty()) + { + // Put the filepath into the stream, prefixed by a "//". + ss << "//" << cANFilePathRenamer.changeToLIMCompatible(common::pathCanonicalize(sm.getFilename(cs->getLocation()).str())); + + // Also put the line info into the stream, as there can be multiple anonymous classes within the same file. + ss << "//" << sm.getSpellingLineNumber(cs->getBeginLoc()) << '_' << sm.getSpellingLineNumber(cs->getEndLoc()); + ss << '_' << sm.getSpellingColumnNumber(cs->getBeginLoc()) << '_' << sm.getSpellingColumnNumber(cs->getEndLoc()); + + break; + } + } + else if (EnumDecl::classofKind(parent->getDeclKind())) + { + const EnumDecl* ed = static_cast(parent); + if (!ed->hasNameForLinkage()) + { + // Put the filepath into the stream, prefixed by a "//". + ss << "//" << cANFilePathRenamer.changeToLIMCompatible(common::pathCanonicalize(sm.getFilename(ed->getLocation()).str())); + + // Also put the line info into the stream, as there can be multiple anonymous classes within the same file. + ss << "//" << sm.getSpellingLineNumber(ed->getBeginLoc()) << '_' << sm.getSpellingLineNumber(ed->getEndLoc()); + ss << '_' << sm.getSpellingColumnNumber(ed->getBeginLoc()) << '_' << sm.getSpellingColumnNumber(ed->getEndLoc()); + + break; + } + } + + // Continue the loop with the parent of the parent + parent = parent->getParent(); + } +} + +void MergeUIDFactory::mangleTypeName(const Type* type, llvm::raw_string_ostream& ss, shared_ptr mangleContext) +{ + // Handle null. + if (!type) + { + //std::cout << "BOOOO" << endl; + ss << ""; + return; + } + /*if (const AutoType* at = dyn_cast_or_null(type)) + { + if (at->isDeduced()) + { + QualType dt = at->getDeducedType();; + mangleTypeName(dt.getTypePtrOrNull(),ss); + return; + } + }*/ + + // Special case for template parameters. + if (const TemplateTypeParmType* t = dyn_cast_or_null(type)) + { + //std::cout << "TOOOO" << endl; + ss << static_cast(*create(t->getDecl(), mangleContext)).getMangledName(); + return; + } + + if (const TemplateSpecializationType *specType = dyn_cast_or_null(type)) + { + if (type->isDependentType()) + { + ss << ""; + //NON_CANONICAL_UNLESS_DEPENDENT_TYPE + //specType->anyDependentTemplateArguments(); + //specType-> + } + else + { + try //this may throw an exception if it fails + { + mangleContext->mangleTypeName(QualType(specType, 0), ss); + } + catch (...) + { + ss << ""; + } + } + + //ss << ""; //there is no other way for now, the above solution just crashes sometimes, maybe we should check if its dependent first, and dont magnel it then + return; + } + + /* + TODO: Look into this in more detail as this can either crash the program or cause important types not get registered with proper ID. + + Examples: + - If we did not allow InjectedClassNameType, 'SomeTemplateClass' would be missed in the following instantiation: + + template class T> class TestClass {}; + template class TestClass; + + - On the other hand if we allowed all dependent types, a simple lambda would crash the mangler: + + int y = 0; + auto lambda = [&](int x) + { + return x + y; + }; + + Yet there might still be cases which could cause either a crash or missed registration. + */ + if (type->isPlaceholderType() || ( (type->isDependentType() && !InjectedClassNameType::classof(type)) ) || FunctionNoProtoType::classof(type)) + { + //std::cout << "FOOOO" << endl; + + //ss << ""; + ss << ""; + return; + } + + //cout << "LOOOOOOOOOOO" << endl; + mangleContext->mangleTypeName(QualType(type, 0), ss); +} + + +unique_ptr MergeUIDFactory::create(const clang::Decl* decl, shared_ptr mangleContext) +{ + if (!decl) + return make_unique("", declToFileName(decl, mangleContext->getASTContext()), 0, 0, false); + + ASTContext& astContext = mangleContext->getASTContext(); + SourceManager& sm = astContext.getSourceManager(); + string mangledName; + + llvm::raw_string_ostream ss(mangledName); + unsigned ln, cn; + string fileName = declToFileName(decl, mangleContext->getASTContext()); + bool isNamespaceDecl = NamespaceDecl::classof(decl); + + // Store line and column numbers. This is not stored for namespaces as all namespaces within the same + // component are considered to be the same if they share their mangled name. + if (isNamespaceDecl) + { + ln = cn = 0; + } + else + { + ln = sm.getSpellingLineNumber(decl->getLocation()); + cn = sm.getSpellingColumnNumber(decl->getLocation()); + } + + // First get the underlying templates, FriendDecl will use its own position not the templates. + if (const FriendDecl* fd = dyn_cast(decl)) + { + if (const TypeSourceInfo* tsi = fd->getFriendType()) + if (const Type* type = tsi->getType().getTypePtrOrNull()) + if (const CXXRecordDecl* classDecl = type->getAsCXXRecordDecl()) + { + // Use the underlying CXXRecordDecl for Friend Class. + decl = classDecl; + + // Use the template described by the class declaration if it's a template. + if (auto td = classDecl->getDescribedClassTemplate()) + decl = td; + } + } + else if (const CXXRecordDecl* rd = dyn_cast(decl)) + { + // Use the template described by the class declaration if it's a template. + if (auto td = rd->getDescribedClassTemplate()) + decl = td; + + // CXXRecordDecl will use the position of the described template. + ln = sm.getSpellingLineNumber(decl->getLocation()); + cn = sm.getSpellingColumnNumber(decl->getLocation()); + } + + // Try to mangle templates. If it's not possible, we still try to mangle their "untemplated" name. + if (const TemplateDecl* td = dyn_cast_or_null(decl)) + { + //cout << "INTO THE TEMLPATE" << endl; + const Type* type = nullptr; + if (const ValueDecl* vd = dyn_cast_or_null(td->getTemplatedDecl())) + type = vd->getType().getTypePtrOrNull(); + else if (const RecordDecl* rd = dyn_cast_or_null(td->getTemplatedDecl())) + type = rd->getTypeForDecl(); + + if (type) + { + mangleTypeName(type, ss, mangleContext); + return make_unique(ss.str(), declToFileName(decl, mangleContext->getASTContext()), ln, cn, false); + } + } + + if (FunctionDecl::classof(decl) && !isa(decl)) + { + const CXXRecordDecl *recordParent = dyn_cast_or_null(static_cast(decl)->getParent()); + + // If this function is only visible from the current translation unit (eg.: static functions, functions in anonymous namespace) + if (static_cast(decl)->getLinkageAndVisibility().getLinkage() != Linkage::ExternalLinkage) + { + // Put the filepath into the stream, prefixed by a "//". + ss << "//" << cANFilePathRenamer.changeToLIMCompatible(common::pathCanonicalize(sm.getFilename(static_cast(decl)->getLocation()).str())); + } + + // Use the built-in mangler to get the mangled name for the function. + if (CXXConstructorDecl::classof(decl)) + mangleContext->mangleName(GlobalDecl(cast(decl), CXXCtorType::Ctor_Complete), ss); + else if (CXXDestructorDecl::classof(decl)) + mangleContext->mangleName(GlobalDecl(cast(decl), CXXDtorType::Dtor_Complete), ss); + else if (recordParent && recordParent->isLambda()) { + ss << "//" << sm.getSpellingLineNumber(decl->getBeginLoc()) << '_' << sm.getSpellingLineNumber(decl->getEndLoc()); + ss << '_' << sm.getSpellingColumnNumber(decl->getBeginLoc()) << '_' << sm.getSpellingColumnNumber(decl->getEndLoc()); + ss << "(lambda)"; + } + else + mangleContext->mangleName(cast(decl), ss); + } + else if (const VarDecl* vd = dyn_cast_or_null(decl)) + { + if (vd->getLinkageAndVisibility().getLinkage() != Linkage::ExternalLinkage) + { + // Put the filepath into the stream, prefixed by a "//". + ss << "//" << cANFilePathRenamer.changeToLIMCompatible(common::pathCanonicalize(sm.getFilename(static_cast(decl)->getLocation()).str())); + } + + if (isa(decl) || isa(vd->getType())) //for some reasion this crashes the mangler... + { + ss << ""; + } + else + { + //very dangerous line, crashes often + mangleContext->mangleName(vd, ss); + } + } + else if (const EnumConstantDecl* ecd = dyn_cast(decl)) + { + // Get the EnumDecl corresponding to the constant. + auto parents = astContext.getParents(*decl); + assert(!parents.empty() && "Container cannot be empty as EnumDecl is always a parent to the enum constant."); + + // Create name for parent first. + const EnumDecl* p = cast(parents.begin()->get()); + declContextName(sm, ss, p); + ss << p->getNameAsString(); + + // Append the name of the constant to it. + ss << "::" << ecd->getNameAsString(); + } + else if (const CXXRecordDecl* rd = dyn_cast(decl)) + { + if (auto td = dyn_cast(decl)) + { + mangleTypeName(td->getTypeForDecl(), ss, mangleContext); + } + else + { + declContextName(sm, ss, rd); + rd->printQualifiedName(ss); + } + } + else if (const DeclContext* parent = dyn_cast(decl)) + { + // Generate name. + declContextName(sm, ss, parent); + + // TODO: Look into this! + // Only one problem remains: class template specializations. Qualified name does not print template + // parameters, so the specializations would get the same ID. + // Once again, we assign the source location to it. + /*if (const CXXRecordDecl* spec = dyn_cast(decl)) + { + spec = spec->getDefinition(); + if (spec) + { + SourceLocation loc = spec->getSourceRange().getBegin(); + ss << '<' << sm.getFilename(loc) << "//" << sm.getSpellingLineNumber(loc) << '_' << sm.getSpellingColumnNumber(loc) << '>'; + } + else + ss << ""; + }*/ + + // Append the qualified name to the stream + if (NamedDecl::classof(decl)) + { + const NamedDecl* nd = cast(decl); + nd->printQualifiedName(ss); + + } + } + else if (const FieldDecl* fd = dyn_cast(decl)) + { + if (const ObjCIvarDecl* iVar = dyn_cast(fd)) + declContextName(sm, ss, iVar->getContainingInterface()); + else + declContextName(sm, ss, fd->getParent()); + + // Append the qualified name to the stream + const NamedDecl* nd = cast(decl); + nd->printQualifiedName(ss); + } + else if (const TemplateTypeParmDecl* nd = dyn_cast_or_null(decl)) + { + // Create name for parent first, which is always a TemplateDecl somewhere on the top. + const Decl* p = decl; + while (true) + { + if (!p) + goto MISSING_ID; + + auto parents = astContext.getParents(*p); + if (parents.empty()) + goto MISSING_ID; + + p = dyn_cast_or_null(parents.begin()->get()); + if (!p) + goto MISSING_ID; + + if (const TemplateDecl* tmp = dyn_cast_or_null(p)) + { + p = tmp->getTemplatedDecl(); + break; + } + else if (CXXRecordDecl::classof(p) || FunctionDecl::classof(p)) + break; + } + + if (!p) + goto MISSING_ID; + + // To mangle "in" the parent's name, we just create an ID for the parent and append the ID of the template parameter after it. + auto uid = create(p, mangleContext); + ss << static_cast(*uid).getMangledName(); + + // Append the name of the parameter to it. + ss << "::<" << nd->getNameAsString() << ">"; + } + else + { + MISSING_ID: + ss << ""; + } + + return make_unique(ss.str(), fileName, ln, cn, isNamespaceDecl); +} + +std::unique_ptr MergeUIDFactory::createTypeId(const clang::QualType type, shared_ptr mangleContext) +{ + string mangledName; + llvm::raw_string_ostream ss(mangledName); + mangleTypeName(type.getTypePtrOrNull(), ss, mangleContext); + return make_unique(ss.str(), declToFileName(nullptr, mangleContext->getASTContext()), 0, 0, false); +} + +std::string MergeUIDFactory::declToFileName(const clang::Decl* decl, ASTContext& astContext) +{ + if (!decl) + return ""; + + clang::SourceLocation loc = decl->getLocation(); + if (loc.isMacroID()) + loc = astContext.getSourceManager().getExpansionLoc(loc); // we need this, as for code in macros, the spellingloc has no file attached to it + + return cANFilePathRenamer.changeToLIMCompatible(common::pathCanonicalize(astContext.getSourceManager().getFilename(loc).str())); +} diff --git a/cl/CAN2Lim/src/clangHelpers.cpp b/cl/CAN2Lim/src/clangHelpers.cpp new file mode 100644 index 0000000..7f0fbb2 --- /dev/null +++ b/cl/CAN2Lim/src/clangHelpers.cpp @@ -0,0 +1,110 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "../inc/clangHelpers.h" + +#include +#include + +using namespace clang; + +bool isDefinition(const clang::TagDecl * decl) +{ + return decl->isCompleteDefinition(); +} + +bool isDefinition(const clang::FunctionDecl * decl) +{ + return decl->getDefinition() == decl; +} + +bool isDefinition(const clang::ObjCProtocolDecl * decl) +{ + return decl->isThisDeclarationADefinition(); +} + +bool isDefinition(const clang::ObjCCategoryDecl * decl) +{ + return true; +} + +bool isDefinition(const clang::ObjCInterfaceDecl * decl) +{ + return decl->isThisDeclarationADefinition(); +} + +bool isDefinition(const clang::ValueDecl * decl) +{ + return false; +} + +bool isDefinition(const clang::VarDecl * decl) +{ + if (decl->isStaticDataMember()) + return decl->hasInit() || decl->isThisDeclarationADefinition() != clang::VarDecl::DeclarationOnly; + else + return decl->isThisDeclarationADefinition() != clang::VarDecl::DeclarationOnly; +} + +bool isDefinition(const clang::FieldDecl * decl) +{ + return true; +} + +bool isDefinition(const clang::ObjCMethodDecl * decl) +{ + return decl->isThisDeclarationADefinition(); +} + +bool isDefinition(const clang::NamespaceDecl * decl) +{ + return true; +} + +bool isDefinition(const clang::Decl * decl) +{ + if(const TagDecl * td = dyn_cast_or_null(decl)) + return isDefinition(td); + else if (const FunctionDecl * fd = dyn_cast_or_null(decl)) + return isDefinition(fd); + else if (const VarDecl * vd = dyn_cast_or_null(decl)) + return isDefinition(vd); + else + { + //std::cout << "ERROR, undhandled isDefinition kind" << std::endl; + return false; + } +} + +const Decl* getLocalDefinition(const clang::Decl * decl) +{ + if(const TagDecl * td = dyn_cast_or_null(decl)) + return td->getDefinition(); + else if (const FunctionDecl * fd = dyn_cast_or_null(decl)) + return fd->getDefinition(); + else if (const VarDecl * vd = dyn_cast_or_null(decl)) + return vd->getDefinition(); + else + { + //std::cout << "ERROR, undhandled getDefinition kind" << std::endl; + return nullptr; + } +} + diff --git a/cl/CAN2Lim/src/main.cpp b/cl/CAN2Lim/src/main.cpp new file mode 100644 index 0000000..837c926 --- /dev/null +++ b/cl/CAN2Lim/src/main.cpp @@ -0,0 +1,529 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include +#include "../inc/messages.h" +#include "../inc/ASTVisitor.h" +#include "../inc/MergeUID.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "../inc/clangHelpers.h" + +#include +#include +#include +#include +#include + +#define PROGRAM_NAME "CAN2Lim" +#define EXECUTABLE_NAME PROGRAM_NAME + +#include "MainCommon.h" + +using namespace std; +using namespace columbus; +using namespace common; +using namespace clang; + +#define BUFFERSIZE 8192 +#define STATMEMSIZE size + +static string listFile; +static string out; +static bool dLIMML = false; +static bool dGraphml= false; +bool pathLower = false; +string changePathFrom; +string changePathTo; +string g_filterfile; +int maxThreads = 0; + +static list inputFiles; + +static bool ppList (const common::Option *o, char *argv[]) { + listFile = argv[0]; + return true; +} + +static bool ppOut (const common::Option *o, char *argv[]) { + out = argv[0]; + return true; +} + +static bool ppPathLower (const common::Option *o, char *argv[]) { + pathLower = true; + return true; +} + +static bool ppLimDump (const common::Option *o, char *argv[]) { + dLIMML = true; + return true; +} + +static bool dumpGRAPHML(const Option *o, char *argv[]) { + dGraphml= true; + return true; +} + +static void ppFile(char *filename) { + inputFiles.push_back(filename); +} + +static bool ppFilterPath (const Option *o, char *argv[]) { + g_filterfile = argv[0]; + return true; +} + +static bool ppMaxThreads(const Option* o, char* argv[]) { + maxThreads = common::str2int(argv[0]); + return true; +} + +const common::Option OPTIONS_OBJ [] = { + { false, "-ilist", 1, "listfile", 0, common::OT_WC, ppList, NULL, "List file containing input filenames" }, + { false, "-out", 1, "outputfile", 0, common::OT_WC, ppOut, NULL, "Output file" }, + { false, "-pathlower", 0, "", 0, common::OT_NONE, ppPathLower, NULL, "Paths are converted to lower case for writting out" }, + { false, "-dLIMML", 0, "", 0, common::OT_NONE, ppLimDump, NULL, "Create LIMML dump" }, + { false, "-dGRAPHML", 0, "", 0, common::OT_WC, dumpGRAPHML, NULL, "Dump graphml to lim" }, + { false, "-maxThreads", 1, CL_KIND_NUMBER, 0, OT_WE | OT_WC, ppMaxThreads, NULL, "This parameter sets the maximum number of threads the Can2Lim can start. The default value is the number of available CPU cores on the current system."}, + CL_FLTP + COMMON_CL_ARGS +}; + + +void checkInputFiles() { + + if (!listFile.empty()) + loadStringListFromFile(listFile, inputFiles); + + if (inputFiles.empty()) + { + WriteMsg::write(CMSG_CAN2LIM_NO_INPUT_FILE); + clError(); + } + + if (inputFiles.size() == 1) + { + if (out.empty()) + out = pathRemoveExtension(*inputFiles.begin()) + ".lim"; + } + else + { + if (out.empty()) + out = "noname.lim"; + } +} + +static inline void setStartTime(uint64_t *time) { + timestat usedtime= getProcessUsedTime(); + *time= usedtime.user + usedtime.system; +} + +static inline void setElapsedTime(uint64_t *time) { + timestat usedtime= getProcessUsedTime(); + *time= usedtime.user + usedtime.system - *time; +} + +static inline void updateMemStat(uint64_t *max_mem) { + memstat ms = getProcessUsedMemSize(); + if (*max_mem < ms.STATMEMSIZE) { + *max_mem = ms.STATMEMSIZE; + } +} + +// The threadPool calls the () operator of this class +class MetricsWorker : public columbus::thread::Task +{ +public: + MetricsWorker(clang::metrics::Invocation& metricsInvocation, const tooling::FixedCompilationDatabase& compilationDatabase + , queue& compilationUnitNames, boost::shared_mutex& taskLockSharedMutex) + : metricsInvocation(metricsInvocation) + , compilationDatabase(compilationDatabase) + , compilationUnitNames(compilationUnitNames) + , taskLockSharedMutex(taskLockSharedMutex) + { + } + + void operator()() + { + // Breaks when there is no more work to do (When compilationUnitNames is empty) + while (true) + { + vector compilationsUnitsForCurrentThread; + { + // Take the name of the next compilation unit to process + columbus::thread::ThreadPool::TaskLock lock(taskLockSharedMutex); + if (compilationUnitNames.empty()) + break; + compilationsUnitsForCurrentThread.push_back(compilationUnitNames.front()); + compilationUnitNames.pop(); + } + // Invoke clang-metrics with the given compilation unit name + metricsInvocation.invoke(compilationDatabase, compilationsUnitsForCurrentThread); + } + + } + +private: + clang::metrics::Invocation& metricsInvocation; + const tooling::FixedCompilationDatabase& compilationDatabase; + queue& compilationUnitNames; + boost::shared_mutex& taskLockSharedMutex; +}; + +// The threadPool calls the () operator of this class +class CAN2LimWorker : public columbus::thread::Task +{ +public: + CAN2LimWorker(queue& compilationUnitNames, const tooling::FixedCompilationDatabase& compilationDatabase, GlobalASTConversionInfo_ThreadSafe& globalConversionInfo, MergeUIDFactory& uidFactory, uint64_t& mem, boost::shared_mutex& taskLockSharedMutex) + : uidFactory(uidFactory) + , compilationUnitNames(compilationUnitNames) + , compilationDatabase(compilationDatabase) + , globalConversionInfo(globalConversionInfo) + , mem(mem) + , taskLockSharedMutex(taskLockSharedMutex) + { + } + void operator()() + { + // Breaks when there is no more work to do (When compilationUnitNames is empty) + while (true) + { + string compilationUnitName; + { + // Take the name of the next compilation unit to process + columbus::thread::ThreadPool::TaskLock lock(taskLockSharedMutex); + if (compilationUnitNames.empty()) + break; + compilationUnitName = compilationUnitNames.front(); + compilationUnitNames.pop(); + } + // Setup clang tool + ASTConversionInfo conversionInfo(compilationUnitName.c_str(), compilationUnitName, globalConversionInfo, uidFactory); + tooling::ClangTool tool(compilationDatabase, { compilationUnitName }); + unique_ptr factory = newConvert2LimActionFactory(conversionInfo); + tool.clearArgumentsAdjusters(); + tool.appendArgumentsAdjuster(tooling::getClangStripOutputAdjuster()); + tool.appendArgumentsAdjuster(tooling::getInsertArgumentAdjuster("-fsyntax-only", tooling::ArgumentInsertPosition::BEGIN)); + + WriteMsg::write(CMSG_CAN2LIM_CONVERTING, compilationUnitName.c_str()); + // Run clang tool + tool.run(factory.get()); + { + columbus::thread::ThreadPool::TaskLock lock(taskLockSharedMutex); + updateMemStat(&mem); + } + } + } + +private: + MergeUIDFactory& uidFactory; + queue& compilationUnitNames; + const tooling::FixedCompilationDatabase& compilationDatabase; + GlobalASTConversionInfo_ThreadSafe& globalConversionInfo; + uint64_t& mem; + boost::shared_mutex& taskLockSharedMutex; +}; + +CANFilePathRenamer cANFilePathRenamer(changePathFrom, changePathTo); + +int main(int argc, char *argv[]) { + uint64_t conversiontime = 0; + uint64_t totaltime = 0; + uint64_t mem = 0; + int notExistedFiles = 0; + int existedFiles = 0; + + WriteMsg::setAutomaticFlush(true); + + MAIN_BEGIN + + MainInit(argc, argv, "-"); + + WriteMsg::setSetTimestampPrefixes(true); + + setStartTime(&totaltime); + checkInputFiles(); + + // Initialize LIM + columbus::RefDistributorStrTable limStrTable; + columbus::RefDistributorStrTable cppStrTable; + + const string rootName = "global namespace"; + lim::asg::Factory limFact(limStrTable, rootName, columbus::lim::asg::limLangCpp); + + auto rootNode = limFact.getRoot(); + //set the root package attributes which is not defined + rootNode->setAccessibility(lim::asg::ackNone); + rootNode->setIsStatic(false); + rootNode->setDemangledName(rootName); + + updateMemStat(&mem); + setStartTime(&conversiontime); + + MergeUIDFactory uidFactory; + unique_ptr metricsOutput = make_unique(uidFactory); + LimOrigin limOrigin; + GlobalASTConversionInfo globalConversionInfo(limFact, *metricsOutput, limOrigin); + + vector> compilationUnitsByComponent; + unordered_set astFilesAlreadySeen; + + WriteMsg::write(WriteMsg::mlNormal, "\nBased on the input list, the following components will be analyzed:\n"); + // Read the component and ast filenames + for (const string& componentFileName : inputFiles) + { + WriteMsg::write(WriteMsg::mlNormal,"%s", componentFileName.c_str()); + WriteMsg::write(WriteMsg::mlDebug, "; it's .ast files:"); + WriteMsg::write(WriteMsg::mlNormal, "\n"); + + lim::asg::base::Component& component = limFact.createComponent(componentFileName.c_str()); + limFact.getComponentRootRef().addContains(&component); + limFact.getRoot()->addBelongsTo(component.getId()); + + list temp; + compilationUnitsByComponent.push_back(vector()); + vector& compilationUnits = compilationUnitsByComponent.back(); + + if (!loadStringListFromFile(componentFileName, temp)) + { + WriteMsg::write(CMSG_CAN2LIM_CANT_LOAD_COMPONENT_FILE, componentFileName.c_str()); //Error! + return EXIT_FAILURE; + } + + for (auto it = temp.begin(); it != temp.end(); ++it) + { + const string& astFileName = *it; + if (common::pathFindExtension(astFileName) != "ast") + { // Just skip... + } + else if(!common::pathFileExists(astFileName)) + WriteMsg::write(CMSG_FILE_DOES_NOT_EXIST, it->c_str()); //Error! + else + { + GlobalASTConversionInfo::ASTIdentifier astID(astFileName); + if (globalConversionInfo.componentsOfTU.count(astID) == 0) + { + // If this this is the first time we see this .ast file, we add it to a list, and we will analyze these + compilationUnits.push_back(astFileName); + astFilesAlreadySeen.insert(astFileName); + WriteMsg::write(WriteMsg::mlDebug, "\t%s\n",it->c_str()); + } + else + { + WriteMsg::write(WriteMsg::mlDebug, "\t%s (duplicate .ast file, thrown away)\n", it->c_str()); + } + + if (astFilesAlreadySeen.count(astFileName) == 0) + { + // If this .ast file is a copy of another one that we already encountered, we still have to add it as a file (for the DCF to work properly) + string modifiedASTFilename = astFileName.c_str(); + columbus::lim::asg::physical::File *astFileNode = &globalConversionInfo.limFactory.createFile(modifiedASTFilename); + + if(!contains(component.getCompilationUnitListIteratorBegin(), component.getCompilationUnitListIteratorEnd(),astFileNode)) + component.addCompilationUnit(astFileNode); + + globalConversionInfo.limFactory.setFiltered(astFileNode->getId()); + + astFilesAlreadySeen.insert(astFileName); + } + + globalConversionInfo.componentsOfTU[astID].insert(&component); + } + } + + existedFiles++; + } + WriteMsg::write(WriteMsg::mlNormal, "\n"); + + // Check maxThreads + if (maxThreads == 0) + maxThreads = columbus::thread::ThreadPool::getNumberOfCores(); + + // Call clang-metrics + + const tooling::FixedCompilationDatabase compilationDatabase(".", { "-fno-delayed-template-parsing" }); // Fishy? + + updateMemStat(&mem); + uint64_t metrics_calc_total_time = 0; + setStartTime(&metrics_calc_total_time); + + WriteMsg::write(WriteMsg::mlNormal, "Clang-metrics has started processing all .ast files, calculating common code metrics (Multithread:%d) ... \n", maxThreads); + bool clangMetricsHalsteadDebug = false; + bool clangMetricsRangeDebug = false; + + bool clangMetricsProcessingTraceDebug = false; + //cout << "Message level is " << WriteMsg::getMessageLevel() << endl; + if (WriteMsg::getMessageLevel() >= WriteMsg::mlDebug) { + clangMetricsProcessingTraceDebug = true; + } + + // Create Invocation object that stores data across multiple invocation calls + clang::metrics::Invocation metricsInvocation(std::move(metricsOutput), clang::metrics::InvokeOptions{ clangMetricsHalsteadDebug,clangMetricsRangeDebug,clangMetricsProcessingTraceDebug }); + // Analyze only one component at a time + for (auto it = compilationUnitsByComponent.begin(); it != compilationUnitsByComponent.end(); it++) + { + columbus::thread::ThreadPool threadPool(maxThreads); + queue compilationUnitNames; + + // Setup a queue that will be accessed by all threads, holding the names of all the compilationUnits they must process between them + for (const auto& compilationUnitName : *it) + compilationUnitNames.push(compilationUnitName); + + // Create all the threads, the threadPool calls their () operator and they start analyzing the compilationsUnits in compilationUnitNames + for (int i = 0; i < maxThreads; i++) + threadPool.add(columbus::thread::ThreadPool::PtrTask(new MetricsWorker(metricsInvocation, compilationDatabase, compilationUnitNames, threadPool.getTaskLockMutex()))); + + threadPool.wait(); + } + + // Call the metricsInvocation aggregate method and take ownership of the output object holding the results + metricsOutput = metricsInvocation.aggregate(); + WriteMsg::write(WriteMsg::mlNormal, "Clang-metrics has finished!\n\n"); + + setElapsedTime(&metrics_calc_total_time); + + // Call the conversions from the ASTs to LIM + + WriteMsg::write(WriteMsg::mlNormal, "Conversion of each .ast file to LIM nodes has started (Multithread:%d) ... \n", maxThreads); + updateMemStat(&mem); + uint64_t ast_conversion_total_time = 0; + setStartTime(&ast_conversion_total_time); + + // Create threadsafe wrapper of the globalConversionInfo object + GlobalASTConversionInfo_ThreadSafe globalInfoThreadSafe(globalConversionInfo); + // Analyze only one component at a time + for (auto it = compilationUnitsByComponent.begin(); it != compilationUnitsByComponent.end(); it++) + { + columbus::thread::ThreadPool threadPool(maxThreads); + queue compilationUnitNames; + + // Setup a queue that will be accessed by all threads, holding the names of all the compilationUnits they must process between them + for (const auto& compilationUnitName : *it) + compilationUnitNames.push(compilationUnitName); + + // Create all the threads, the threadPool calls their () operator and they start analyzing the compilationsUnits in compilationUnitNames + for (int i = 0; i < maxThreads; i++) + threadPool.add(columbus::thread::ThreadPool::PtrTask(new CAN2LimWorker(compilationUnitNames, compilationDatabase, globalInfoThreadSafe, uidFactory, mem, threadPool.getTaskLockMutex()))); + + threadPool.wait(); + } + + WriteMsg::write(WriteMsg::mlNormal, "Conversion is finished!\n\n"); + + // Post process of the whole conversion + WriteMsg::write(WriteMsg::mlNormal, "Post processing the LIM (linking, comments, calculating global metrics, etc.) ...\n"); + globalConversionInfo.finalizeConversion(); + WriteMsg::write(WriteMsg::mlNormal, "Post processing is finished.\n"); + + setElapsedTime(&ast_conversion_total_time); + setElapsedTime(&conversiontime); + + updateMemStat(&mem); + + if (existedFiles == 0) { + WriteMsg::write(CMSG_CAN2LIM_NO_LCSI_LOADED); + return common::retASGLoadError; + } + + uint64_t savingtime = 0; + setStartTime(&savingtime); + std::list headerList; + headerList.push_back(&limOrigin); + + try { + limFact.save(out, headerList, false); + } catch (const IOException& e) { + common::WriteMsg::write(CMSG_CAN2LIM_FACTORY_SAVE_ERROR, e.getMessage().c_str()); + } + + setElapsedTime(&savingtime); + + string filterfile = out.substr(0, out.find_last_of('.')) + ".flim"; + try { + limFact.saveFilter(filterfile); + } catch (const IOException&) { + common::WriteMsg::write(CMSG_CAN2LIM_FILTER_SAVE_PROBLEM, filterfile.c_str()); + } + + // Save the LIM as .limml file (if flag is set) + uint64_t limmltime = 0; + setStartTime(&limmltime); + + if (dLIMML) { + string limmlFile = common::pathRemoveExtension(out) + ".limml"; + ofstream ofLimml(limmlFile.c_str()); + if (!ofLimml.is_open()) { + common::WriteMsg::write(CMSG_CAN2LIM_LIMML_DUMP_PROBLEM, limmlFile.c_str()); + } else { + lim::asg::VisitorLIMML *visitorLimml = new lim::asg::VisitorLIMML(ofLimml, ""); + lim::asg::AlgorithmPreorder ap; + ap.setVisitSpecialNodes(true, true); + ap.run(limFact, *visitorLimml); + delete visitorLimml; + ofLimml.close(); + } + } + + // Save the lim as .graphml file (if flag is set) + if (dGraphml) { + io::GraphmlIO ioToDumpGraphml((out + ".graphml").c_str(), "Lim"); + std::set edgeFilter; + lim::asg::VisitorGraphml visitorToDumpGraphml(ioToDumpGraphml, edgeFilter); + lim::asg::AlgorithmPreorder ap; + ap.run(limFact, visitorToDumpGraphml); + } + + setElapsedTime(&limmltime); + setElapsedTime(&totaltime); + + WriteMsg::write(CMSG_CAN2LIM_STATISTICS); + WriteMsg::write(CMSG_CAN2LIM_CONVERSION_PHASE_TIME, ((float)conversiontime)/100); + WriteMsg::write(CMSG_CAN2LIM_METRICS_CALC_TIME, ((float)metrics_calc_total_time)/100); + WriteMsg::write(CMSG_CAN2LIM_CONVERSION_TIME, ((float)ast_conversion_total_time)/100); + WriteMsg::write(CMSG_CAN2LIM_SAVE_TIME, ((float)savingtime)/100); + WriteMsg::write(CMSG_CAN2LIM_DUMP_TIME, ((float)limmltime)/100); + WriteMsg::write(CMSG_CAN2LIM_TOTAL_TIME, ((float)totaltime)/100); + WriteMsg::write(CMSG_CAN2LIM_PEAK_MEMORY, ((float)mem)/1048576); + WriteMsg::write(CMSG_CAN2LIM_NOT_EXISTED_FILES, notExistedFiles); + + MAIN_END + + //throw 20; + + return EXIT_SUCCESS; +} diff --git a/cl/CANConfig/CMakeLists.txt b/cl/CANConfig/CMakeLists.txt new file mode 100644 index 0000000..daff907 --- /dev/null +++ b/cl/CANConfig/CMakeLists.txt @@ -0,0 +1,12 @@ +set (PROGRAM_NAME CANConfig) + +set (SOURCES + main.cpp + + messages.h +) + +add_executable(${PROGRAM_NAME} ${SOURCES}) +add_dependencies(${PROGRAM_NAME} ${COLUMBUS_GLOBAL_DEPENDENCY}) +target_link_libraries(${PROGRAM_NAME} common ${COMMON_EXTERNAL_LIBRARIES}) +set_visual_studio_project_folder(${PROGRAM_NAME} TRUE) diff --git a/cl/CANConfig/main.cpp b/cl/CANConfig/main.cpp new file mode 100644 index 0000000..a2b8fc4 --- /dev/null +++ b/cl/CANConfig/main.cpp @@ -0,0 +1,416 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include +#include +#include +#include +#include +#include +#include "messages.h" + +#define PROGRAM_NAME "CANConfig" +#define EXECUTABLE_NAME "CANConfig" + +#define PREDEFINED_MACROS_FILENAME "predefined_macros.txt" +#define PREDEFINED_MACROS_FULL_FILENAME "predefined_macros_full.txt" +#define CAN_CONFIG_FILENAME "can.ini" + +#include +#include +#include +#include + +using namespace common; +using namespace std; + +static string directoryOfTheBinary; +static string outputDirectoryName = "."; +static string inputCompiler; +static string outputFilenname = CAN_CONFIG_FILENAME; +static bool gccMode = false; + +static string clangInternalMacros[] = { + "----" +}; + +static string clInternalMacros[] = { + "----" +}; + +bool loadFileByLine(const string& filename, vector& lines) { + string line; + ifstream input(filename.c_str()); + if (input.is_open()) { + while (input.good()) { + getline(input, line); + if (!line.empty()) + lines.push_back(line); + } + input.close(); + } else + return false; + + return true; +} + +#ifdef GENERATE_MACROS + +static string createPredefinedMacroCheckClangCommandLine(bool cpp ) { + return "echo \" \" | \"" + inputCompiler + "\" -x " + + (cpp ? " c++" : " c") + + " - -E -dM"; +} + +static void reformatLine(string& line) { + if (line.size() > 8) + line = line.substr(8); // "#define " +} + + +static void createClangMacros(bool cpp, vector& macros) { + string const tmpFile = "tmpfile"; + string command = createPredefinedMacroCheckClangCommandLine(cpp); + + if (common::run(command, false, tmpFile)) { + WriteMsg::write( CMSG_COMMAND_EXECUTION_FAILED, command.c_str()); + exit(EXIT_FAILURE); + } + + if (!loadFileByLine(tmpFile, macros)) { + WriteMsg::write( CMSG_LOAD_PREDEFINED_MACROS_FAILED, tmpFile.c_str()); + exit(EXIT_FAILURE); + } + + for_each(macros.begin(), macros.end(), reformatLine); + sort(macros.begin(), macros.end()); + + pathDeleteFile(tmpFile); +} + +static void writeMacroIfNeeded(ofstream& out, const string& line, bool clang) { + + if (clang) { + for (size_t i = 0; i < sizeof(clangInternalMacros) / sizeof(string); ++i) + if (line.find(clangInternalMacros[i]) == 0) + return; + } else { + + for (size_t i = 0; i < sizeof(clInternalMacros) / sizeof(string); ++i) + if (line.find(clInternalMacros[i]) == 0) + return; + } + out << line << endl; +} + +static void generateMacroFile(const vector& cMacros, const vector& cppMacros, bool clang) { + vector::const_iterator cit = cMacros.begin(); + vector::const_iterator cppit = cppMacros.begin(); + + const string predefinedMacroFileName = outputDirectoryName + DIRDIVSTRING PREDEFINED_MACROS_FILENAME; + ofstream pdefMacroFile(predefinedMacroFileName.c_str()); + const string predefinedMacroFullFileName = outputDirectoryName + DIRDIVSTRING PREDEFINED_MACROS_FULL_FILENAME; + ofstream pdefMacroFullFile(predefinedMacroFullFileName.c_str()); + + if (!pdefMacroFile.is_open()) { + WriteMsg::write( CMSG_ERROR_OPEN_FILE, predefinedMacroFileName.c_str()); + exit(EXIT_FAILURE); + } + + if(!pdefMacroFullFile.is_open()) { + if(pdefMacroFile.is_open()) + pdefMacroFile.close(); + WriteMsg::write( CMSG_ERROR_OPEN_FILE, predefinedMacroFullFileName.c_str()); + exit(EXIT_FAILURE); + } + + while (cit != cMacros.end() && cppit != cppMacros.end()) { + if (*cit == *cppit) { + writeMacroIfNeeded(pdefMacroFile, *cit, clang); + pdefMacroFullFile << *cit << endl; + ++cit; + ++cppit; + } else if (*cit < *cppit) { + writeMacroIfNeeded(pdefMacroFile, *cit, clang); + pdefMacroFullFile << *cit << endl; + ++cit; + } else { + writeMacroIfNeeded(pdefMacroFile, *cppit, clang); + pdefMacroFullFile << *cppit << endl; + ++cppit; + } + } + + while (cit != cMacros.end()) { + writeMacroIfNeeded(pdefMacroFile, *cit, clang); + pdefMacroFullFile << *cit << endl; + ++cit; + } + + while (cppit != cppMacros.end()) { + writeMacroIfNeeded(pdefMacroFile, *cppit, clang); + pdefMacroFullFile << *cppit << endl; + ++cppit; + } + + pdefMacroFile.close(); + pdefMacroFullFile.close(); +} +#endif + +#ifdef __linux + +enum class LanguageConfiguration +{ + c, + cpp +}; + +enum class LibCppConfiguration +{ + none, + libstdcpp, + libcpp +}; + +static string createIncludeSearchCheckCommandLine(LanguageConfiguration languageConfiguration, LibCppConfiguration libcppConfiguration) +{ + string langConfig; + switch (languageConfiguration) + { + case LanguageConfiguration::c : langConfig = "c"; break; + case LanguageConfiguration::cpp : langConfig = "c++"; break; + } + + string libcppConfig; + switch (libcppConfiguration) + { + case LibCppConfiguration::none : break; + case LibCppConfiguration::libstdcpp : libcppConfig = "-stdlib=libstdc++"; break; + case LibCppConfiguration::libcpp : libcppConfig = "-stdlib=libc++"; break; + } + + return "echo \" \" | \"" + inputCompiler + "\" -x " + langConfig + " " + libcppConfig + " -v -E -"; +} + + + + +static void getIncludes(LanguageConfiguration languageConfiguration, LibCppConfiguration libcppConfiguration, list& includes) +{ + string const tmpFile = "tmpfile"; + string command = createIncludeSearchCheckCommandLine(languageConfiguration, libcppConfiguration); + + if (common::run(command, false, tmpFile, tmpFile)) { + WriteMsg::write( CMSG_COMMAND_EXECUTION_FAILED, command.c_str()); + exit(EXIT_FAILURE); + } + + vector lines; + if (!loadFileByLine(tmpFile, lines)) { + WriteMsg::write( CMSG_LOAD_COMPILER_OUTPUT_FAILED, tmpFile.c_str()); + exit(EXIT_FAILURE); + } + + bool inside = false; + for(vector::const_iterator lineIt = lines.begin(); lineIt != lines.end(); ++lineIt) { + if (lineIt->find("#include <...> search starts here:") == 0) + inside = true; + else if (lineIt->find("End of search list.") == 0) + inside = false; + else if (inside) + includes.push_back(trim(*lineIt)); + } + + pathDeleteFile(tmpFile); +} + +static void createIncludes(LanguageConfiguration languageConfiguration, LibCppConfiguration libcppConfiguration, const string& iniFileName, const string& section) { + list includes; + getIncludes(languageConfiguration, libcppConfiguration, includes); + + int counter = 1; + for (const auto& path : includes) + common::writePrivateProfileString(section.c_str(), ("path" + toString(counter++)).c_str(), path.c_str(), iniFileName.c_str()); +} + +static void generateClangIncludeSearchConfig() { + string iniFileName = outputDirectoryName + DIRDIVSTRING + outputFilenname; + createIncludes(LanguageConfiguration::c, LibCppConfiguration::none, iniFileName, "IncludePath_c"); + createIncludes(LanguageConfiguration::cpp, LibCppConfiguration::libcpp, iniFileName, "IncludePath_cpp"); +} + +static void generateGccIncludeSearchConfig() { + string iniFileName = outputDirectoryName + DIRDIVSTRING + outputFilenname; + createIncludes(LanguageConfiguration::c, LibCppConfiguration::none, iniFileName, "IncludePath_c"); + createIncludes(LanguageConfiguration::cpp, LibCppConfiguration::none, iniFileName, "IncludePath_cpp"); +} + + +#elif defined _WIN32 + +static void generateClIncludeSearchConfig(const vector& cIncludes, const vector& cppIncludes) { + string iniFileName = outputDirectoryName + DIRDIVSTRING + outputFilenname; + + int counter = 0; + for (vector::const_iterator incIt = cIncludes.begin(); incIt != cIncludes.end(); ++incIt) + common::writePrivateProfileString("IncludePath_c", ("path" + toString(counter++)).c_str(), incIt->c_str(), iniFileName.c_str()); + + counter = 0; + for (vector::const_iterator incIt = cppIncludes.begin(); incIt != cppIncludes.end(); ++incIt) + common::writePrivateProfileString("IncludePath_cpp", ("path" + toString(counter++)).c_str(), incIt->c_str(), iniFileName.c_str()); + +} + + +static string createPredefinedMacroCheckClCommandLine(bool cpp, const string& filename) { + return CL_PAR_PLUS + inputCompiler + CL_PAR_PLUS + " /EP " + + (cpp ? " /TP /Bx" : " /TC /B1") + + "\"" + directoryOfTheBinary + "Paramcheck.exe\" " + + filename; +} + +static void createClMacrosAndIncludes(bool cpp, vector& macros, vector& includes) { + + string const tmpInputFile = "tmpfile_empty"; + ofstream emptyFile(tmpInputFile.c_str()); + if (emptyFile.is_open()) + emptyFile.close(); + else { + WriteMsg::write( CMSG_ERROR_CREATE_FILE, tmpInputFile.c_str()); + exit(EXIT_FAILURE); + } + + string const tmpFileOut = "tmpfile1"; + string const tmpFileError = "tmpfile2"; + + string command = createPredefinedMacroCheckClCommandLine(cpp, tmpInputFile); + if (common::run(command, false, tmpFileOut, tmpFileError)) { + WriteMsg::write( CMSG_COMMAND_EXECUTION_FAILED, command.c_str()); + pathDeleteFile(tmpInputFile); + pathDeleteFile(tmpFileOut); + pathDeleteFile(tmpFileError); + exit(EXIT_FAILURE); + } + + vector macrosAndIncludes; + if (!loadFileByLine(tmpFileOut, macrosAndIncludes)) { + WriteMsg::write( CMSG_LOAD_PREDEFINED_MACROS_FAILED, tmpFileOut.c_str()); + pathDeleteFile(tmpInputFile); + pathDeleteFile(tmpFileOut); + pathDeleteFile(tmpFileError); + exit(EXIT_FAILURE); + } + + for (vector::const_iterator it = macrosAndIncludes.begin(); it != macrosAndIncludes.end(); ++it) { + if (it->find("#define") == 0) + macros.push_back(*it); + else if (!it->empty()) + includes.push_back(removeQuotes(*it)); + } + +#ifdef GENERATE_MACROS + for_each(macros.begin(), macros.end(), reformatLine); + sort(macros.begin(), macros.end()); +#endif + + pathDeleteFile(tmpInputFile); + pathDeleteFile(tmpFileOut); + pathDeleteFile(tmpFileError); + +} + +#endif + +static bool ppOutDir(const Option *o, char *argv[]) { + static bool alreadySet = false; + if (alreadySet) + WriteMsg::write( CMSG_OUTPUT_DIRECTORY_PARAMETER_IS_SETED, outputDirectoryName.c_str()); + outputDirectoryName = argv[0]; + alreadySet = true; + return true; +} + +static bool ppConfigfileName(const Option *o, char *argv[]) +{ + outputFilenname = argv[0]; + return true; +} + +static bool ppGcc(const Option *o, char *argv[]) +{ + gccMode = true; + return true; +} + +static void ppFile(char *filename) { + if (!inputCompiler.empty()) + WriteMsg::write( CMSG_COMPILER_IS_SETED, inputCompiler.c_str()); + + inputCompiler = filename; +} + +const Option OPTIONS_OBJ[] = { + { false, "-out", 1, "outputdirectory", 0, OT_WS | OT_WC, ppOutDir, NULL, "Place the output files into the given directory"}, + { false, "-filename", 1, "filename", 0, OT_WS | OT_WC, ppConfigfileName, NULL, "Set the name of the generated config file"}, + { false, "-gcc", 0, "", 0, OT_NONE, ppGcc, NULL, "Generate configuration for GCC"}, + + COMMON_CL_ARGS +}; + + +int main(int argc, char *argv[]) +{ + MAIN_BEGIN + + MainInit(argc, argv, "-"); + + directoryOfTheBinary = common::getExecutableProgramDir(); + + vector cMacros; + vector cppMacros; + +#ifdef __linux + if (inputCompiler.empty()) + inputCompiler = "clang"; + + if (gccMode) + generateGccIncludeSearchConfig(); + else + generateClangIncludeSearchConfig(); + +#elif defined _WIN32 + if (inputCompiler.empty()) + inputCompiler = "cl"; + + vector cIncludes; + vector cppIncludes; + + createClMacrosAndIncludes(false, cMacros, cIncludes); + createClMacrosAndIncludes(true, cppMacros, cppIncludes); + + generateClIncludeSearchConfig(cIncludes, cppIncludes); +#endif + + MAIN_END + + return 0; +} + diff --git a/cl/CANConfig/messages.h b/cl/CANConfig/messages.h new file mode 100644 index 0000000..bd68475 --- /dev/null +++ b/cl/CANConfig/messages.h @@ -0,0 +1,33 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _CANCONFIG_M_H_ +#define _CANCONFIG_M_H_ + +#define CMSG_COMMAND_EXECUTION_FAILED WriteMsg::mlError, "Execution of the command [%s] is failed!\n" +#define CMSG_LOAD_PREDEFINED_MACROS_FAILED WriteMsg::mlError, "Failed to load the file [%s] containing the predefined macros!\n" +#define CMSG_LOAD_COMPILER_OUTPUT_FAILED WriteMsg::mlError, "Failed to load the temporary file [%s] with the redirected output of the compiler!\n" +#define CMSG_UNDETERMINED_GCC_VERSION WriteMsg::mlWarning, "Can not determine the version of the gcc! [%s]\n" +#define CMSG_ERROR_OPEN_FILE WriteMsg::mlError, "Can not open file [%s] for writing!\n" +#define CMSG_ERROR_CREATE_FILE WriteMsg::mlError, "Can not create file [%s]!\n" +#define CMSG_OUTPUT_DIRECTORY_PARAMETER_IS_SETED WriteMsg::mlWarning, "Output directory parameter is already set to [%s]\n" +#define CMSG_COMPILER_IS_SETED WriteMsg::mlWarning, "Compiler is already set to [%s]\n" + +#endif diff --git a/cl/CANLib/CMakeLists.txt b/cl/CANLib/CMakeLists.txt new file mode 100644 index 0000000..7bb9915 --- /dev/null +++ b/cl/CANLib/CMakeLists.txt @@ -0,0 +1,12 @@ +set (PROGRAM_NAME CANLib) + +set (SOURCES + src/main.cpp + + inc/messages.h +) + +add_executable(${PROGRAM_NAME} ${SOURCES}) +add_dependencies(${PROGRAM_NAME} ${COLUMBUS_GLOBAL_DEPENDENCY}) +target_link_libraries(${PROGRAM_NAME} archivecpp common io ${COMMON_EXTERNAL_LIBRARIES}) +set_visual_studio_project_folder(${PROGRAM_NAME} TRUE) diff --git a/cl/CANLib/inc/messages.h b/cl/CANLib/inc/messages.h new file mode 100644 index 0000000..e457231 --- /dev/null +++ b/cl/CANLib/inc/messages.h @@ -0,0 +1,35 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _CANLIB_M_H_ +#define _CANLIB_M_H_ + +#define CMSG_MSG_MISSING_ARCHIVE_ERROR WriteMsg::mlError, "Unable to open archive file '%s'!\n" +#define CMSG_MSG_MISSING_ARCHIVE_NAME_ERROR WriteMsg::mlError, "Archive filename is missing!\n" +#define CMSG_MSG_FAILED_TO_ADD_ERROR WriteMsg::mlError, "Failed to add file `%s` to the archive! (%s)\n" +#define CMSG_MSG_FAILED_TO_EXTRACT_ERROR WriteMsg::mlError, "Failed to extract file `%s` from the archive! (%s)\n" +#define CMSG_MSG_FAILED_TO_DELETE_ERROR WriteMsg::mlError, "Failed to delete file `%s` from the archive! (%s)\n" +#define CMSG_MSG_NO_OPERATION_MODE_ERROR WriteMsg::mlError, "No operation mode is set!\n" +#define CMSG_MSG_NO_SUCH_FILE_IN_THE_ARCHIVE_ERROR WriteMsg::mlError, "There is no '%s' file in the archive!\n" +#define CMSG_MSG_FILE_ERROR WriteMsg::mlError, "Error! '%s' (%s)\n" +#define CMSG_MSG_OUTPUT_MUST_BE_A_DIRECTORY_ERROR WriteMsg::mlError, "If there are more than one files to be extracted, then the output `%s` must be a directory!\n" +#define CMSG_MSG_FILE_ALREADY_EXISTS_WARNING WriteMsg::mlWarning, "Warning! File '%s' already exists in the archive and replace is disabled!\n" + +#endif diff --git a/cl/CANLib/src/main.cpp b/cl/CANLib/src/main.cpp new file mode 100644 index 0000000..805d87a --- /dev/null +++ b/cl/CANLib/src/main.cpp @@ -0,0 +1,461 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#define PROGRAM_NAME "CANLib" +#define EXECUTABLE_NAME "CANLib" + +#ifdef __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdelete-non-abstract-non-virtual-dtor" + #pragma clang diagnostic ignored "-Wtautological-undefined-compare" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../inc/messages.h" + + +using namespace std; +using namespace common; +using namespace columbus; + +namespace +{ + enum class OperationMode + { + None, + Add, + Extract, + Delete, + List + } operationMode = OperationMode::None; + + + bool replaceEnabled = true; + bool filenameOnly = false; + bool noWriteTime = false; + bool oneLevelOnly = false; + list listOfInputFiles; + string archiveFilename; + string outputFilename; + + bool ppDisableReplace( const Option *o, char *argv[]) + { + replaceEnabled = false; + return true; + } + + bool ppOMAdd( const Option *o, char *argv[]) + { + operationMode = OperationMode::Add; + return true; + } + + bool ppOMDelete( const Option *o, char *argv[]) + { + operationMode = OperationMode::Delete; + return true; + } + + bool ppOMExtract( const Option *o, char *argv[]) + { + operationMode = OperationMode::Extract; + return true; + } + + bool ppOMList( const Option *o, char *argv[]) + { + operationMode = OperationMode::List; + return true; + } + + bool ppList (const Option *o, char *argv[]) + { + return loadStringListFromFile(argv[0], listOfInputFiles); + } + + bool ppOutput (const Option *o, char *argv[]) + { + outputFilename = argv[0]; + return true; + } + + bool ppFilenameOnly(const Option *o, char *argv[]) + { + filenameOnly = true; + return true; + } + + bool ppOneLevelOnly(const Option *o, char *argv[]) + { + oneLevelOnly = true; + return true; + } + + bool ppNoTime(const Option *o, char *argv[]) + { + noWriteTime = true; + return true; + } +} + +static void ppFile( char *filename) +{ + if (archiveFilename.empty()) + archiveFilename = filename; + else + listOfInputFiles.push_back(filename); +} + + +const Option OPTIONS_OBJ [] = { + { false, "-add", 0, "", 1, OT_WS, ppOMAdd, NULL, "Operation: add ast files to the archive"}, + { false, "-delete", 0, "", 1, OT_WS, ppOMDelete, NULL, "Operation: delete ast files from the archive"}, + { false, "-extract", 0, "", 1, OT_WS, ppOMExtract, NULL, "Operation: extract ast files from the archive"}, + { false, "-list", 0, "", 1, OT_WS, ppOMList, NULL, "Operation: list the content of the archive"}, + { false, "-nowritetime", 0, "", 1, OT_WS, ppNoTime, NULL, "Do not print the TIME column during the list operation"}, + { false, "-output", 1, "", 0, OT_WC, ppOutput, NULL, "Output filename for extraction operation"}, + { false, "-disablereplace", 0, "", 0, OT_WS, ppDisableReplace, NULL, "Disable replacing files, which already exist in the archive"}, + { false, "-filenameonly", 0, "", 0, OT_WS, ppFilenameOnly, NULL, "Store and extract files with the filename only"}, + { false, "-onelevelonly", 0, "", 0, OT_WS, ppOneLevelOnly, NULL, "Store files with maximum one subdirectory only"}, + CL_INPUT_LIST + COMMON_CL_ARGS +}; + + +namespace +{ + + int execute() + { + int result = EXIT_SUCCESS; + + if (archiveFilename.empty()) + { + WriteMsg::write(CMSG_MSG_MISSING_ARCHIVE_NAME_ERROR); + return EXIT_FAILURE; + } + if (operationMode == OperationMode::None) + { + return EXIT_FAILURE; + } + + if (operationMode == OperationMode::Add) + { + string directoryname = common::pathRemoveFileSpec(archiveFilename); + if (archiveFilename != directoryname) + common::makeDirectory(directoryname); + + list srcEntries; + unique_ptr srcZip; + unique_ptr tempZip; + string tempZipPath = archiveFilename + ".tmp"; + map filesToAdd; + + if (common::pathFileExists(archiveFilename)) + { + try + { + srcZip = ZipFile::OpenForReading(archiveFilename); + srcEntries = srcZip->GetEntries(); + } + catch (const columbus::Exception& error) + { + printf("ERROR: %s\n", error.getMessage().c_str()); + } + } + + tempZip = ZipFile::OpenForWriting(tempZipPath); + + for (auto filename : listOfInputFiles) + { + string modifiedFilename; + filename = correctDirDivsToUnix(filename); + + if (filenameOnly) + modifiedFilename = common::pathFindFileName(filename); + + else if (oneLevelOnly) + { + std::stack pathPartStack; + + for (const auto& part : boost::filesystem::path(filename)) + pathPartStack.push(part); + + boost::filesystem::path shortName; + for (int i = 0; i < 2 && !pathPartStack.empty(); ++i) + { + shortName = pathPartStack.top() / shortName; + pathPartStack.pop(); + } + + modifiedFilename = shortName.string(); + } + else + modifiedFilename = filename; + + if (auto sameSrcEntryIt = find_if(srcEntries.begin(), srcEntries.end(), [&modifiedFilename](const ZipArchiveEntry& v) { return v.GetFullName() == modifiedFilename; }); sameSrcEntryIt != srcEntries.end()) + { + if (!replaceEnabled) + { + WriteMsg::write(CMSG_MSG_FILE_ALREADY_EXISTS_WARNING, modifiedFilename.c_str()); + continue; + } + else + { + srcEntries.erase(sameSrcEntryIt); + } + + } + + if (filenameOnly) + filesToAdd[filename] = filename; + else if (oneLevelOnly) + filesToAdd[filename] = modifiedFilename; + else + filesToAdd[filename] = filename; + } + + for (const auto& srcZipEntry : srcEntries) + tempZip->CopyFromZip(*srcZip, srcZipEntry.GetIndex()); + + for (const auto& fileToAdd : filesToAdd) + { + try + { + tempZip->AddFile(fileToAdd.first, fileToAdd.second); + } + catch (const columbus::Exception& error) + { + WriteMsg::write(CMSG_MSG_FAILED_TO_ADD_ERROR, fileToAdd.first.c_str(), error.toString().c_str()); + result = EXIT_FAILURE; + break; + } + } + + tempZip->Close(); + if (srcZip) + srcZip->Close(); + + remove(archiveFilename.c_str()); + rename(tempZipPath.c_str(), archiveFilename.c_str()); + + } + else if (operationMode == OperationMode::Extract) + { + const bool dirOutput = common::pathIsDirectory(outputFilename); + + if (listOfInputFiles.size() > size_t(1) && !dirOutput) + { + WriteMsg::write(CMSG_MSG_OUTPUT_MUST_BE_A_DIRECTORY_ERROR, outputFilename.c_str()); + return EXIT_FAILURE; + } + + if (listOfInputFiles.empty()) + { + auto zipArchive = ZipFile::OpenForReading(archiveFilename); + for (size_t entryIndex = 0; entryIndex < zipArchive->GetEntriesCount(); ++entryIndex) + { + auto zipEntry = zipArchive->GetEntry(entryIndex); + listOfInputFiles.push_back(zipEntry->GetFullName()); + } + } + + auto zipArchive = ZipFile::OpenForReading(archiveFilename); + for (auto filename : listOfInputFiles) + { + filename = correctDirDivsToUnix(filename); + if (!zipArchive->IsInArchive(filename)) + { + WriteMsg::write(CMSG_MSG_NO_SUCH_FILE_IN_THE_ARCHIVE_ERROR, filename.c_str()); + return EXIT_FAILURE; + } + + try + { + if (filenameOnly && outputFilename.empty()) + { + zipArchive->ExtractFile(filename); + } + else if (outputFilename.empty()) + { + string directoryname = common::pathRemoveFileSpec(filename); + if (filename != directoryname) + common::makeDirectory(directoryname); + zipArchive->ExtractFile(filename, filename); + } + else // filenameOnly && !outputFilename.empty() + { // !filenameOnly && !outputFilename.empty() + if (dirOutput) + { + if (filenameOnly) + { + string nameWithoutDirectory = common::pathFindFileName(filename); + zipArchive->ExtractFile(filename, outputFilename + DIRDIVCHAR + nameWithoutDirectory); + } + else + { + string directoryname = common::pathRemoveFileSpec(filename); + if (filename != directoryname) + common::makeDirectory(outputFilename + DIRDIVCHAR + directoryname); + zipArchive->ExtractFile(filename, outputFilename + DIRDIVCHAR + filename); + } + } + else + { + zipArchive->ExtractFile(filename, outputFilename); + } + } + } + catch (const std::runtime_error& error) + { + WriteMsg::write(CMSG_MSG_FAILED_TO_EXTRACT_ERROR, filename.c_str(), error.what()); + return EXIT_FAILURE; + } + } + } + else if (operationMode == OperationMode::Delete) + { + auto zipArchive = ZipFile::OpenForReading(archiveFilename); + auto srcEntries = zipArchive->GetEntries(); + + for (auto filename : listOfInputFiles) + { + filename = correctDirDivsToUnix(filename); + + if (auto sameSrcEntryIt = find_if(srcEntries.begin(), srcEntries.end(), [&filename](const ZipArchiveEntry& v) { return v.GetFullName() == filename; }); sameSrcEntryIt != srcEntries.end()) + { + srcEntries.erase(sameSrcEntryIt); + } + else + { + WriteMsg::write(CMSG_MSG_NO_SUCH_FILE_IN_THE_ARCHIVE_ERROR, filename.c_str()); + return EXIT_FAILURE; + } + } + + string tempZipPath = archiveFilename + ".tmp"; + auto tempZip = ZipFile::OpenForWriting(tempZipPath); + + for (const auto& srcZipEntry : srcEntries) + tempZip->CopyFromZip(*zipArchive, srcZipEntry.GetIndex()); + + tempZip->Close(); + zipArchive->Close(); + + remove(archiveFilename.c_str()); + rename(tempZipPath.c_str(), archiveFilename.c_str()); + } + else if (operationMode == OperationMode::List) + { + try + { + FILE *outputFile = nullptr; + if (!outputFilename.empty()) + { + outputFile = fopen(outputFilename.c_str(), "wt"); + if (outputFile == nullptr) + { + WriteMsg::write(CMSG_MSG_FILE_ERROR, outputFilename.c_str(), "Failed to open"); + return EXIT_FAILURE; + } + WriteMsg::setOuputFile(outputFile); + } + + auto zipArchive = ZipFile::OpenForReading(archiveFilename); + if (noWriteTime) + { + WriteMsg::write(WriteMsg::mlNormal, " # ORIG SIZE CMPR CRC-32 NAME\n"); + WriteMsg::write(WriteMsg::mlNormal, "----- ------------ ---- -------- ------\n"); + for (uint32_t entryIndex = 0; entryIndex < zipArchive->GetEntriesCount(); ++entryIndex) + { + auto zipEntry = zipArchive->GetEntry(entryIndex); + WriteMsg::write(WriteMsg::mlNormal, "%5zu %12zu %3zu%% %8X %s\n", + entryIndex, + zipEntry->GetUncompressedSize(), + zipEntry->GetUncompressedSize() > 0 ? zipEntry->GetCompressedSize() * 100 / zipEntry->GetUncompressedSize() : 0, + zipEntry->GetCrc32(), + zipEntry->GetFullName().c_str() + ); + } + } + else + { + WriteMsg::write(WriteMsg::mlNormal, " # ORIG SIZE CMPR DATE TIME CRC-32 NAME\n"); + WriteMsg::write(WriteMsg::mlNormal, "----- ------------ ---- ---------- ------------ -------- ------\n"); + for (uint32_t entryIndex = 0; entryIndex < zipArchive->GetEntriesCount(); ++entryIndex) + { + auto zipEntry = zipArchive->GetEntry(entryIndex); + time_t lastWriteTime = zipEntry->GetLastWriteTime(); + char buffer[30]; + strftime(buffer, 30, "%Y-%m-%d %H:%M:%S %Z", localtime(&lastWriteTime)); + + WriteMsg::write(WriteMsg::mlNormal, "%5zu %12zu %3zu%% %s %8X %s\n", + entryIndex, + zipEntry->GetUncompressedSize(), + zipEntry->GetUncompressedSize() > 0 ? zipEntry->GetCompressedSize() * 100 / zipEntry->GetUncompressedSize() : 0, + buffer, + zipEntry->GetCrc32(), + zipEntry->GetFullName().c_str() + ); + } + } + + if (outputFile != nullptr) + { + WriteMsg::setOuputFile(stdout); + fclose(outputFile); + } + } + catch (const std::runtime_error& error) + { + WriteMsg::write(CMSG_MSG_FILE_ERROR, archiveFilename.c_str(), error.what()); + return EXIT_FAILURE; + } + } + else if (operationMode == OperationMode::None) + { + WriteMsg::write(CMSG_MSG_NO_OPERATION_MODE_ERROR); + return EXIT_FAILURE; + } + + return result; + } +} + +int main( int argc, char *argv[]) { + int result; + WriteMsg::setAutomaticFlush(true); + MAIN_BEGIN + MainInit( argc, argv, "-"); + result = execute(); + + MAIN_END + + fflush(stdout); + return result; +} diff --git a/cl/CANLink/CMakeLists.txt b/cl/CANLink/CMakeLists.txt new file mode 100644 index 0000000..8400bf1 --- /dev/null +++ b/cl/CANLink/CMakeLists.txt @@ -0,0 +1,12 @@ +set (PROGRAM_NAME CANLink) + +set (SOURCES + src/main.cpp + + inc/messages.h +) + +add_executable(${PROGRAM_NAME} ${SOURCES}) +add_dependencies(${PROGRAM_NAME} ${COLUMBUS_GLOBAL_DEPENDENCY}) +target_link_libraries(${PROGRAM_NAME} common io ${COMMON_EXTERNAL_LIBRARIES}) +set_visual_studio_project_folder(${PROGRAM_NAME} TRUE) diff --git a/cl/CANLink/inc/messages.h b/cl/CANLink/inc/messages.h new file mode 100644 index 0000000..eb9c545 --- /dev/null +++ b/cl/CANLink/inc/messages.h @@ -0,0 +1,99 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _CANLINK_M_H_ +#define _CANLINK_M_H_ + +//main.cpp +#define CMSG_NO_INPUT_FILE common::WriteMsg::mlNormal, "\nNo input file!\n\n" +#define CMSG_NO_OUTPUT_FILE common::WriteMsg::mlError, "\nNo output file was set.\n" +#define CMSG_CAN_NOT_OPEN_OUTPUT_FILE common::WriteMsg::mlError, "Failed to open '%s' file for writting.\n" +#define CMSG_STATISTICS common::WriteMsg::mlNormal, "\nStatistics:\n" +#define CMSG_STAT_LINKING_TIME common::WriteMsg::mlNormal, "\tLinking time :%lu sec/100\n" +#define CMSG_STAT_FILTERING_TIME common::WriteMsg::mlNormal, "\tFiltering time :%lu sec/100\n" +#define CMSG_STAT_USER_TIME common::WriteMsg::mlNormal, "\tTotal user time :%lu sec/100\n" +#define CMSG_STAT_SYSTEM_TIME common::WriteMsg::mlNormal, "\tTotal system time :%lu sec/100\n" +#define CMSG_STAT_PEAK_MEMORY_USAGE common::WriteMsg::mlNormal, "\tPeak memory usage :%lu MByte\n" +#define CMSG_SAVED common::WriteMsg::mlDDDebug, "%s is saved.\n" + +#define CMSG_STAT_HEADER_OUTPUT_FILE "Output file" +#define CMSG_STAT_HEADER_NUMBER_OF_INPUT_FILES "Number of input files" +#define CMSG_STAT_HEADER_NUMBER_OF_CSI_FILES "Number of csi files" +#define CMSG_STAT_HEADER_NUMBER_OF_WARNINGS "Number of warnings" +#define CMSG_STAT_HEADER_LINKING_TIME "Linking time (s)" +#define CMSG_STAT_HEADER_FILTERING_TIME "Filtering time (s)" +#define CMSG_STAT_HEADER_USER_TIME "Total user time (s)" +#define CMSG_STAT_HEADER_SYSTEM_TIME "Total system time (s)" +#define CMSG_STAT_HEADER_CPU_TIME "Total cpu time (s)" +#define CMSG_STAT_HEADER_PEAK_MEMORY_USAGE "Peak memory usage (MByte)" +#define CMSG_STAT_HEADER_AVERAGE_NUMBER_OF_NODES "Average number of nodes" +#define CMSG_STAT_HEADER_NUMBER_OF_NODES_IN_THE_LINKED_ASG "Number of nodes in the linked ASG" + +//AutoCheck.cpp +#define CMSG_LINKINDEXORDER_IS_NOT_CORRECT WriteMsg::mlWarning, "LinkIndexOrder is not correct in %s : 2 node index is not right, ID-s first %s : %s second %s : %s\n" +#define CMSG_THE_HASH_IS_DIFFERENT WriteMsg::mlWarning, "Hash code(0x%x) to node with %u ID is not equal. The old node hash was 0x%x\n" +#define CMSG_THE_HASH_IS_OK WriteMsg::mlDDDDebug, "Hash ok %u \n" +#define CMSG_THE_NODE_NOT_CONNECTED_TO_NODE WriteMsg::mlWarning, "Node with %u ID is not connected to Node with %u ID\n" +#define CMSG_THE_NODE_IS_MISSING_FORM_TREE WriteMsg::mlWarning, "Node with %u ID is missing form tree of Node with %u ID\n" +#define CMSG_THE_NODE_HAS_NOT_MANGLEDNAME WriteMsg::mlDDebug, "Node with %u ID hasn't mangledname\n" +#define CMSG_EXTRA_SYMBOLS WriteMsg::mlNormal, "Extra symbols :\n" +#define CMSG_MISSING_SYMBOLS WriteMsg::mlNormal, "Missing symbols :\n" +#define CMSG_SYMBOL_TYPE_CHECK WriteMsg::mlNormal, "Symbol type check :\n" +#define CMSG_SYMBOL_TYPE_IS_NOT_CORRECT WriteMsg::mlWarning, "Symbol type is not correct : %s\n" +#define CMSG_ERROR_IN_CHECK WriteMsg::mlWarning, "Error in check\n" +#define CMSG_NODE_CONNECT_MULTI_TIMES_TO WriteMsg::mlWarning, "Node with %u ID connect multi times to node with %u ID\n" +#define CMSG_NODE_IS_NOT_EXIST_IN_COMPILATION_UNIT WriteMsg::mlWarning, "Node is not exist in compilation unit %s: %u ID\n" +#define CMSG_EXIST_MORE_THEN_ONE_FROM_INDEXABLE_NODE_WITH_SAME_PROPERTY WriteMsg::mlWarning, "Exist more then one from indexable node with same property: first %s %u ID and %s %u ID\n" + +//Linker.cpp + +#define CMSG_IS_NOT_SAME_KIND_SIMBOL WriteMsg::mlWarning,"Not a same kind of symbol! %s %s != %s\n" +#define CMSG_THERE_IS_NO_INPUT WriteMsg::mlError, "ERROR: There is no input for the linker!\n" +#define CMSG_FILE_BEGIN WriteMsg::mlNormal, "FILE BEGIN %s\n" +#define CMSG_FILE_END WriteMsg::mlNormal, "FILE END %s\n" +#define CMSG_FILE_BEGIN_ACSI WriteMsg::mlNormal, "ACSI %s: FILE BEGIN %s\n" +#define CMSG_FILE_END_ACSI WriteMsg::mlNormal, "ACSI %s: FILE END %s\n" +#define CMSG_IN_FILE WriteMsg::mlError, "%s :in %s file\n", e.getMessage().c_str() , inputFileNames.front().c_str() +#define CMSG_FILE_PEAK_MEMORY_USAGE WriteMsg::mlDebug, "\tFile %s : Peak memory usage :%lu Mb\n" +#define CMSG_THE_FILE_IS_NOT_EXIST WriteMsg::mlWarning, "WARNING: The %s file does not exist!\n" +#define CMSG_THE_FILE_IS_NOT_EXIST_ERROR WriteMsg::mlError, "ERROR: The %s file does not exist!\n" +#define CMSG_SAME_NODE_EXSIST WriteMsg::mlDDDebug, "Two equivalent nodes (%s) in the first ASG: (%d == %d)\n" +#define CMSG_DOUBLE_SYMBOL_DEFINITION_ABOUT WriteMsg::mlWarning, "Error: Double Symbol definition about dst %s in %s and src %s in %s\n" +#define CMSG_WEAK_SYMBOL_IS_DROPPED_FROM WriteMsg::mlDDebug, "Weak symbol %s is dropped from %s\n" +#define CMSG_ERROR_AT_LINKER_EXCEPTION WriteMsg::mlError, "Error at Linker::copyAllPositionNode exception (%s)." +#define CMSG_THE_NODE_PARENT_NOT_FOUND WriteMsg::mlDDDDebug, "The %d node parent not found in the linked but the original has \n" +#define CMSG_THE_ID_IN_THE_LINKED_ASG_IS WriteMsg::mlDDDDebug, "The %d id in the linked asg is %d\n" +#define CMSG_DOUBLE_MAIN_SYMBOL_DEFINITION WriteMsg::mlError, "Error: Double main Symbol definition\n" +#define CMSG_THE_NODE_IN_THE_SRC_CORRESPOND WriteMsg::mlDDDDebug, "The node %d (in the src) correspond to %d node in the (dest asg )\n" +#define CMSG_DUPLICATED_NODE_IN_THE_SPANNING_TREE WriteMsg::mlError, "Duplicated node in the spanning-tree:%u (%s)\n" +#define CMSG_VISITED_NODES WriteMsg::mlDebug, "Visited nodes:%d\n" +#define CMSG_NUMBER_OF_TYPE_NODES WriteMsg::mlDebug, "Number of Type nodes:%u\n" +#define CMSG_GLOBAL_NODES WriteMsg::mlDebug, "Global nodes:\n" +#define CMSG_PS_PU_DEBUG WriteMsg::mlDebug, " %s:%u\n" +#define CMSG_TOTAL_GLOBAL_NODES WriteMsg::mlDebug, "Total global nodes:%u\n" +#define CMSG_DOUBLE_OVERWRITE_WARNING WriteMsg::mlWarning, "Warning!: Double overwrite! The %d is already overwritten with %d and can not overwrite with the %d again!\n" +#define CMSG_OVERWRITING_NON_SYMBOL WriteMsg::mlDebug, "Overwritting (non-symbol) %d node with %d node." +#define CMSG_MAPPING_NODES WriteMsg::mlDebug, "Mapping (%d) to the %d node.\n" +#define CMSG_DOUBLE_MAPPING_WARNING WriteMsg::mlDebug, "Node (%d) is not maped to the %d node because some other node is already mapped to this node and it can be overwritten!\n" +//node comp +#define CMSG_OPERATOR_USE_ITSEFT common::WriteMsg::mlDebug, " < operator of node is not good !!! use itseft for decide node kind %s (%d)\n" +#define CMSG_NOT_RULE_FOR_NODE common::WriteMsg::mlDDDDebug, "Not rule to compare the %s node kind. (%d, %d)\n" + +#endif diff --git a/cl/CANLink/src/main.cpp b/cl/CANLink/src/main.cpp new file mode 100644 index 0000000..3378ed4 --- /dev/null +++ b/cl/CANLink/src/main.cpp @@ -0,0 +1,162 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include +#include +#include "ReleaseVersion.h" +#include "ErrorCodes.h" +#include "common/inc/Arguments.h" +#include "common/inc/Stat.h" +#include +#include +#include +#include + +#define PROGRAM_NAME "CANLink" +#define EXECUTABLE_NAME "CANLink" + +#include "MainCommon.h" + +#include "common/inc/WriteMessage.h" +#include "../inc/messages.h" + +using namespace std; +using namespace common; +using namespace columbus; + +//-- data for CmdLine --> +static string out; +static string statFile; +static string fList; //list of the input files +static string fltpFile; +static list listOfAst; + +#define STATMEMSIZE size + +// Callback methods for argument processing +static bool ppOut(const Option *o, char *argv[]) { + out= argv[0]; + return true; +} + +static void ppFile(char *filename) { + listOfAst.push_back(filename); +} + +static bool ppFilter (const common::Option *o, char *argv[]) { + fltpFile = argv[0]; + return true; +} + +static bool ppStat(const Option *o, char *argv[]) { + statFile = argv[0]; + return true; +} + +static bool ppList (const Option *o, char *argv[]) { + fList = argv[0]; + return true; +} + +const Option OPTIONS_OBJ[]= { + {false, "-out", 1, "filename", 1, OT_WS | OT_WC, ppOut, NULL, "Output file name"}, + {false, "-stat", 1, "filename", 0, OT_WS | OT_WC, ppStat, NULL, "Create statistic file for wrapper environment"}, + {false, "-ilist", 1, "filename", 0, OT_WC, ppList, NULL, "Name of the file, which contains the list of the input files"}, + {false, "-filter", 1, "filterfile", 0, OT_WC, ppFilter, NULL, "Filter file (files are taken account only from these paths)"}, + + COMMON_CL_ARGS}; + +int main(int argc, char *argv[]) +{ + int ret = EXIT_SUCCESS; + WriteMsg::setAutomaticFlush(true); + MAIN_BEGIN + + MainInit(argc, argv, "-"); + + loadStringListFromFile(fList, listOfAst); + if (listOfAst.empty()) { + common::WriteMsg::write(CMSG_NO_INPUT_FILE); + clError(); + } + + if (out.empty()) { + WriteMsg::write(CMSG_NO_OUTPUT_FILE); + clError(); + } + + size_t numberOfAstFiles = 0; + ofstream outputListFile(out.c_str()); + if (outputListFile) + { + for (auto& inputFileName : listOfAst) + { + if (pathFindExtension(inputFileName) == ".ast") + ++numberOfAstFiles; + outputListFile << indep_fullpath(inputFileName) << "\n"; + } + } + else + { + WriteMsg::write(CMSG_CAN_NOT_OPEN_OUTPUT_FILE, out.c_str()); + ret = EXIT_FAILURE; + } + + timestat totaltime = getProcessUsedTime(); + memstat memory = getProcessUsedMemSize(); + + WriteMsg::write(CMSG_STATISTICS); + WriteMsg::write(CMSG_STAT_USER_TIME, totaltime.user); + WriteMsg::write(CMSG_STAT_SYSTEM_TIME, totaltime.system); + WriteMsg::write(CMSG_STAT_PEAK_MEMORY_USAGE, memory.size / (1024 * 1024)); + + if (!statFile.empty()) { + bool writeHeader = false; + + if (!pathFileExists(statFile, false)) + writeHeader = true; + + io::CsvIO csv(statFile, io::IOBase::omAppend); + + if (writeHeader) { + csv.writeColumn(CMSG_STAT_HEADER_CPU_TIME); + csv.writeColumn(CMSG_STAT_HEADER_PEAK_MEMORY_USAGE); + csv.writeColumn(CMSG_STAT_HEADER_OUTPUT_FILE); + csv.writeColumn(CMSG_STAT_HEADER_NUMBER_OF_INPUT_FILES); + csv.writeColumn(CMSG_STAT_HEADER_NUMBER_OF_CSI_FILES); + csv.writeColumn(CMSG_STAT_HEADER_NUMBER_OF_WARNINGS); + csv.writeNewLine(); + } + + string path; + common::pathCanonicalize(path, out); + csv.writeColumn((totaltime.user + totaltime.system) / 100.0f); + csv.writeColumn((unsigned long)(memory.size / (1024 * 1024))); + csv.writeColumn(path); + csv.writeColumn((unsigned int)listOfAst.size()); + csv.writeColumn((unsigned int)numberOfAstFiles); + csv.writeColumn(WriteMsg::getWasWarning()); + csv.writeNewLine(); + } + + MAIN_END + + return ret; +} diff --git a/cl/ClangTidy2Graph/CMakeLists.txt b/cl/ClangTidy2Graph/CMakeLists.txt new file mode 100644 index 0000000..90ad5cf --- /dev/null +++ b/cl/ClangTidy2Graph/CMakeLists.txt @@ -0,0 +1,18 @@ +set (PROGRAM_NAME ClangTidy2Graph) + +set (SOURCES + src/main.cpp + src/ResultConverter.cpp + + inc/messages.h + inc/defines.h + inc/ResultConverter.h +) + +add_executable(${PROGRAM_NAME} ${SOURCES}) +add_dependencies(${PROGRAM_NAME} ${COLUMBUS_GLOBAL_DEPENDENCY}) +target_link_libraries(${PROGRAM_NAME} lim2graph graphsupport lim graph rul common csi strtable io ${COMMON_EXTERNAL_LIBRARIES}) +add_copy_next_to_the_binary_dependency(${PROGRAM_NAME} ClangTidy.rul) +set_visual_studio_project_folder(${PROGRAM_NAME} TRUE) + + diff --git a/cl/ClangTidy2Graph/ClangTidy.rul b/cl/ClangTidy2Graph/ClangTidy.rul new file mode 100644 index 0000000..c261d69 --- /dev/null +++ b/cl/ClangTidy2Graph/ClangTidy.rul @@ -0,0 +1,8562 @@ + + + + + + ClangTidy + + + + + + + + false + false + abseil-duration-addition + abseil + + true + Duration Addition + <p>Check for cases where addition should be performed in the absl::Time domain. When adding two values, and one is known to be an absl::Time, we can infer that the other should be interpreted as an absl::Duration of a similar scale, and make that inference explicit.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Original - Addition in the integer domain</span> <span class="dt">int</span> x; absl::Time t; <span class="dt">int</span> result = absl::ToUnixSeconds(t) + x; <span class="co">// Suggestion - Addition in the absl::Time domain</span> <span class="dt">int</span> result = absl::ToUnixSeconds(t + absl::Seconds(x));</code></pre></div> <p>(Clang-Tidy original name: abseil-duration-addition)</p> + + + + Major + + + + + + + false + false + abseil-duration-comparison + abseil + + true + Duration Comparison + <p>Checks for comparisons which should be in the absl::Duration domain instead of the floating point or integer domains.</p> <p>N.B.: In cases where a Duration was being converted to an integer and then compared against a floating-point value, truncation during the Duration conversion might yield a different result. In practice this is very rare, and still indicates a bug which should be fixed.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Original - Comparison in the floating point domain</span> <span class="dt">double</span> x; absl::Duration d; <span class="kw">if</span> (x &lt; absl::ToDoubleSeconds(d)) ... <span class="co">// Suggested - Compare in the absl::Duration domain instead</span> <span class="kw">if</span> (absl::Seconds(x) &lt; d) ... <span class="co">// Original - Comparison in the integer domain</span> <span class="dt">int</span> x; absl::Duration d; <span class="kw">if</span> (x &lt; absl::ToInt64Microseconds(d)) ... <span class="co">// Suggested - Compare in the absl::Duration domain instead</span> <span class="kw">if</span> (absl::Microseconds(x) &lt; d) ...</code></pre></div> <p>(Clang-Tidy original name: abseil-duration-comparison)</p> + + + + Major + + + + + + + false + false + abseil-duration-conversion-cast + abseil + + true + Duration Conversion Cast + <p>Checks for casts of absl::Duration conversion functions, and recommends the right conversion function instead.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Original - Cast from a double to an integer</span> absl::Duration d; <span class="dt">int</span> i = <span class="kw">static_cast</span>&lt;<span class="dt">int</span>&gt;(absl::ToDoubleSeconds(d)); <span class="co">// Suggested - Use the integer conversion function directly.</span> <span class="dt">int</span> i = absl::ToInt64Seconds(d); <span class="co">// Original - Cast from a double to an integer</span> absl::Duration d; <span class="dt">double</span> x = <span class="kw">static_cast</span>&lt;<span class="dt">double</span>&gt;(absl::ToInt64Seconds(d)); <span class="co">// Suggested - Use the integer conversion function directly.</span> <span class="dt">double</span> x = absl::ToDoubleSeconds(d);</code></pre></div> <p>Note: In the second example, the suggested fix could yield a different result, as the conversion to integer could truncate. In practice, this is very rare, and you should use absl::Trunc to perform this operation explicitly instead.</p> <p>(Clang-Tidy original name: abseil-duration-conversion-cast)</p> + + + + Major + + + + + + + false + false + abseil-duration-division + abseil + + true + Duration Division + <p>absl::Duration arithmetic works like it does with integers. That means that division of two absl::Duration objects returns an int64 with any fractional component truncated toward 0. See <a href="https://github.com/abseil/abseil-cpp/blob/29ff6d4860070bf8fcbd39c8805d0c32d56628a3/absl/time/time.h#L137">this link</a> for more information on arithmetic with absl::Duration.</p> <p>For example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">absl::Duration d = absl::Seconds(<span class="fl">3.5</span>); int64 sec1 = d / absl::Seconds(<span class="dv">1</span>); <span class="co">// Truncates toward 0.</span> int64 sec2 = absl::ToInt64Seconds(d); <span class="co">// Equivalent to division.</span> assert(sec1 == <span class="dv">3</span> &amp;&amp; sec2 == <span class="dv">3</span>); <span class="dt">double</span> dsec = d / absl::Seconds(<span class="dv">1</span>); <span class="co">// WRONG: Still truncates toward 0.</span> assert(dsec == <span class="fl">3.0</span>);</code></pre></div> <p>If you want floating-point division, you should use either the absl::FDivDuration() function, or one of the unit conversion functions such as absl::ToDoubleSeconds(). For example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">absl::Duration d = absl::Seconds(<span class="fl">3.5</span>); <span class="dt">double</span> dsec1 = absl::FDivDuration(d, absl::Seconds(<span class="dv">1</span>)); <span class="co">// GOOD: No truncation.</span> <span class="dt">double</span> dsec2 = absl::ToDoubleSeconds(d); <span class="co">// GOOD: No truncation.</span> assert(dsec1 == <span class="fl">3.5</span> &amp;&amp; dsec2 == <span class="fl">3.5</span>);</code></pre></div> <p>This check looks for uses of absl::Duration division that is done in a floating-point context, and recommends the use of a function that returns a floating-point value.</p> <p>(Clang-Tidy original name: abseil-duration-division)</p> + + + + Major + + + + + + + false + false + abseil-duration-factory-float + abseil + + true + Duration Factory Float + <p>Checks for cases where the floating-point overloads of various absl::Duration factory functions are called when the more-efficient integer versions could be used instead.</p> <p>This check will not suggest fixes for literals which contain fractional floating point values or non-literals. It will suggest removing superfluous casts.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Original - Providing a floating-point literal.</span> absl::Duration d = absl::Seconds(<span class="fl">10.0</span>); <span class="co">// Suggested - Use an integer instead.</span> absl::Duration d = absl::Seconds(<span class="dv">10</span>); <span class="co">// Original - Explicitly casting to a floating-point type.</span> absl::Duration d = absl::Seconds(<span class="kw">static_cast</span>&lt;<span class="dt">double</span>&gt;(<span class="dv">10</span>)); <span class="co">// Suggested - Remove the explicit cast</span> absl::Duration d = absl::Seconds(<span class="dv">10</span>);</code></pre></div> <p>(Clang-Tidy original name: abseil-duration-factory-float)</p> + + + + Major + + + + + + + false + false + abseil-duration-factory-scale + abseil + + true + Duration Factory Scale + <p>Checks for cases where arguments to absl::Duration factory functions are scaled internally and could be changed to a different factory function. This check also looks for arguments with a zero value and suggests using absl::ZeroDuration() instead.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Original - Internal multiplication.</span> <span class="dt">int</span> x; absl::Duration d = absl::Seconds(<span class="dv">60</span> * x); <span class="co">// Suggested - Use absl::Minutes instead.</span> absl::Duration d = absl::Minutes(x); <span class="co">// Original - Internal division.</span> <span class="dt">int</span> y; absl::Duration d = absl::Milliseconds(y / <span class="fl">1000.</span>); <span class="co">// Suggested - Use absl:::Seconds instead.</span> absl::Duration d = absl::Seconds(y); <span class="co">// Original - Zero-value argument.</span> absl::Duration d = absl::Hours(<span class="dv">0</span>); <span class="co">// Suggested = Use absl::ZeroDuration instead</span> absl::Duration d = absl::ZeroDuration();</code></pre></div> <p>(Clang-Tidy original name: abseil-duration-factory-scale)</p> + + + + Major + + + + + + + false + false + abseil-duration-subtraction + abseil + + true + Duration Subtraction + <p>Checks for cases where subtraction should be performed in the absl::Duration domain. When subtracting two values, and the first one is known to be a conversion from absl::Duration, we can infer that the second should also be interpreted as an absl::Duration, and make that inference explicit.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Original - Subtraction in the double domain</span> <span class="dt">double</span> x; absl::Duration d; <span class="dt">double</span> result = absl::ToDoubleSeconds(d) - x; <span class="co">// Suggestion - Subtraction in the absl::Duration domain instead</span> <span class="dt">double</span> result = absl::ToDoubleSeconds(d - absl::Seconds(x)); <span class="co">// Original - Subtraction of two Durations in the double domain</span> absl::Duration d1, d2; <span class="dt">double</span> result = absl::ToDoubleSeconds(d1) - absl::ToDoubleSeconds(d2); <span class="co">// Suggestion - Subtraction in the absl::Duration domain instead</span> <span class="dt">double</span> result = absl::ToDoubleSeconds(d1 - d2);</code></pre></div> <p>Note: As with other clang-tidy checks, it is possible that multiple fixes may overlap (as in the case of nested expressions), so not all occurrences can be transformed in one run. In particular, this may occur for nested subtraction expressions. Running clang-tidy multiple times will find and fix these overlaps.</p> <p>(Clang-Tidy original name: abseil-duration-subtraction)</p> + + + + Major + + + + + + + false + false + abseil-duration-unnecessary-conversion + abseil + + true + Duration Unnecessary Conversion + <p>Finds and fixes cases where absl::Duration values are being converted to numeric types and back again.</p> <p>Floating-point examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Original - Conversion to double and back again</span> absl::Duration d1; absl::Duration d2 = absl::Seconds(absl::ToDoubleSeconds(d1)); <span class="co">// Suggestion - Remove unnecessary conversions</span> absl::Duration d2 = d1; <span class="co">// Original - Division to convert to double and back again</span> absl::Duration d2 = absl::Seconds(absl::FDivDuration(d1, absl::Seconds(<span class="dv">1</span>))); <span class="co">// Suggestion - Remove division and conversion</span> absl::Duration d2 = d1;</code></pre></div> <p>Integer examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Original - Conversion to integer and back again</span> absl::Duration d1; absl::Duration d2 = absl::Hours(absl::ToInt64Hours(d1)); <span class="co">// Suggestion - Remove unnecessary conversions</span> absl::Duration d2 = d1; <span class="co">// Original - Integer division followed by conversion</span> absl::Duration d2 = absl::Seconds(d1 / absl::Seconds(<span class="dv">1</span>)); <span class="co">// Suggestion - Remove division and conversion</span> absl::Duration d2 = d1;</code></pre></div> <p>Unwrapping scalar operations:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Original - Multiplication by a scalar</span> absl::Duration d1; absl::Duration d2 = absl::Seconds(absl::ToInt64Seconds(d1) * <span class="dv">2</span>); <span class="co">// Suggestion - Remove unnecessary conversion</span> absl::Duration d2 = d1 * <span class="dv">2</span>;</code></pre></div> <p>Note: Converting to an integer and back to an absl::Duration might be a truncating operation if the value is not aligned to the scale of conversion. In the rare case where this is the intended result, callers should use absl::Trunc to truncate explicitly.</p> <p>(Clang-Tidy original name: abseil-duration-unnecessary-conversion)</p> + + + + Major + + + + + + + false + false + abseil-faster-strsplit-delimiter + abseil + + true + Faster Strsplit Delimiter + <p>Finds instances of absl::StrSplit() or absl::MaxSplits() where the delimiter is a single character string literal and replaces with a character. The check will offer a suggestion to change the string literal into a character. It will also catch code using absl::ByAnyChar() for just a single character and will transform that into a single character as well.</p> <p>These changes will give the same result, but using characters rather than single character string literals is more efficient and readable.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Original - the argument is a string literal.</span> <span class="kw">for</span> (<span class="kw">auto</span> piece : absl::StrSplit(str, <span class="st">&quot;B&quot;</span>)) { <span class="co">// Suggested - the argument is a character, which causes the more efficient</span> <span class="co">// overload of absl::StrSplit() to be used.</span> <span class="kw">for</span> (<span class="kw">auto</span> piece : absl::StrSplit(str, <span class="st">&#39;B&#39;</span>)) { <span class="co">// Original - the argument is a string literal inside absl::ByAnyChar call.</span> <span class="kw">for</span> (<span class="kw">auto</span> piece : absl::StrSplit(str, absl::ByAnyChar(<span class="st">&quot;B&quot;</span>))) { <span class="co">// Suggested - the argument is a character, which causes the more efficient</span> <span class="co">// overload of absl::StrSplit() to be used and we do not need absl::ByAnyChar</span> <span class="co">// anymore.</span> <span class="kw">for</span> (<span class="kw">auto</span> piece : absl::StrSplit(str, <span class="st">&#39;B&#39;</span>)) { <span class="co">// Original - the argument is a string literal inside absl::MaxSplits call.</span> <span class="kw">for</span> (<span class="kw">auto</span> piece : absl::StrSplit(str, absl::MaxSplits(<span class="st">&quot;B&quot;</span>, <span class="dv">1</span>))) { <span class="co">// Suggested - the argument is a character, which causes the more efficient</span> <span class="co">// overload of absl::StrSplit() to be used.</span> <span class="kw">for</span> (<span class="kw">auto</span> piece : absl::StrSplit(str, absl::MaxSplits(<span class="st">&#39;B&#39;</span>, <span class="dv">1</span>))) {</code></pre></div> <p>(Clang-Tidy original name: abseil-faster-strsplit-delimiter)</p> + + + + Major + + + + + + + false + false + abseil-no-internal-dependencies + abseil + + true + No Internal Dependencies + <p>Warns if code using Abseil depends on internal details. If something is in a namespace that includes the word “internal”, code is not allowed to depend upon it beaucse it’s an implementation detail. They cannot friend it, include it, you mention it or refer to it in any way. Doing so violates Abseil’s compatibility guidelines and may result in breakage. See <a href="https://abseil.io/about/compatibility" class="uri">https://abseil.io/about/compatibility</a> for more information.</p> <p>The following cases will result in warnings:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">absl::strings_internal::foo(); <span class="co">// warning triggered on this line</span> <span class="kw">class</span> foo { <span class="kw">friend</span> <span class="kw">struct</span> absl::container_internal::faa; <span class="co">// warning triggered on this line</span> }; absl::memory_internal::MakeUniqueResult(); <span class="co">// warning triggered on this line</span></code></pre></div> <p>(Clang-Tidy original name: abseil-no-internal-dependencies)</p> + + + + Major + + + + + + + false + false + abseil-no-namespace + abseil + + true + No Namespace + <p>Ensures code does not open namespace absl as that violates Abseil’s compatibility guidelines. Code should not open namespace absl as that conflicts with Abseil’s compatibility guidelines and may result in breakage.</p> <p>Any code that uses:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">namespace</span> absl { ... }</code></pre></div> <p>will be prompted with a warning.</p> <p>See <a href="https://abseil.io/about/compatibility">the full Abseil compatibility guidelines</a> for more information.</p> <p>(Clang-Tidy original name: abseil-no-namespace)</p> + + + + Major + + + + + + + false + false + abseil-redundant-strcat-calls + abseil + + true + Redundant Strcat Calls + <p>Suggests removal of unnecessary calls to absl::StrCat when the result is being passed to another call to absl::StrCat or absl::StrAppend.</p> <p>The extra calls cause unnecessary temporary strings to be constructed. Removing them makes the code smaller and faster.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::string s = absl::StrCat(<span class="st">&quot;A&quot;</span>, absl::StrCat(<span class="st">&quot;B&quot;</span>, absl::StrCat(<span class="st">&quot;C&quot;</span>, <span class="st">&quot;D&quot;</span>))); <span class="co">//before</span> std::string s = absl::StrCat(<span class="st">&quot;A&quot;</span>, <span class="st">&quot;B&quot;</span>, <span class="st">&quot;C&quot;</span>, <span class="st">&quot;D&quot;</span>); <span class="co">//after</span> absl::StrAppend(&amp;s, absl::StrCat(<span class="st">&quot;E&quot;</span>, <span class="st">&quot;F&quot;</span>, <span class="st">&quot;G&quot;</span>)); <span class="co">//before</span> absl::StrAppend(&amp;s, <span class="st">&quot;E&quot;</span>, <span class="st">&quot;F&quot;</span>, <span class="st">&quot;G&quot;</span>); <span class="co">//after</span></code></pre></div> <p>(Clang-Tidy original name: abseil-redundant-strcat-calls)</p> + + + + Major + + + + + + + false + false + abseil-str-cat-append + abseil + + true + Str Cat Append + <p>Flags uses of absl::StrCat() to append to a std::string. Suggests absl::StrAppend() should be used instead.</p> <p>The extra calls cause unnecessary temporary strings to be constructed. Removing them makes the code smaller and faster.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">a = absl::StrCat(a, b); <span class="co">// Use absl::StrAppend(&amp;a, b) instead.</span></code></pre></div> <p>Does not diagnose cases where absl::StrCat() is used as a template argument for a functor.</p> <p>(Clang-Tidy original name: abseil-str-cat-append)</p> + + + + Major + + + + + + + false + false + abseil-string-find-startswith + abseil + + true + String Find Startswith + <p>Checks whether a std::string::find() result is compared with 0, and suggests replacing with absl::StartsWith(). This is both a readability and performance issue.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">string s = <span class="st">&quot;...&quot;</span>; <span class="kw">if</span> (s.find(<span class="st">&quot;Hello World&quot;</span>) == <span class="dv">0</span>) { <span class="co">/* do something */</span> }</code></pre></div> <p>becomes</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">string s = <span class="st">&quot;...&quot;</span>; <span class="kw">if</span> (absl::StartsWith(s, <span class="st">&quot;Hello World&quot;</span>)) { <span class="co">/* do something */</span> }</code></pre></div> <h5 id="options-72">Options</h5> <p>StringLikeClasses</p> <p>Semicolon-separated list of names of string-like classes. By default only std::basic_string is considered. The list of methods to considered is fixed.</p> <p>IncludeStyle</p> <p>A string specifying which include-style is used, llvm or google. Default is llvm.</p> <p>AbseilStringsMatchHeader</p> <p>The location of Abseil’s strings/match.h. Defaults to absl/strings/match.h.</p> <p>(Clang-Tidy original name: abseil-string-find-startswith)</p> + + + + Major + + + + + + + false + false + abseil-string-find-str-contains + abseil + + true + String Find Str Contains + <p>Finds s.find(...) == string::npos comparisons (for various string-like types) and suggests replacing with absl::StrContains().</p> <p>This improves readability and reduces the likelihood of accidentally mixing find() and npos from different string-like types.</p> <p>By default, “string-like types” includes ::std::basic_string, ::std::basic_string_view, and ::absl::string_view. See the StringLikeClasses option to change this.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::string s = <span class="st">&quot;...&quot;</span>; <span class="kw">if</span> (s.find(<span class="st">&quot;Hello World&quot;</span>) == std::string::npos) { <span class="co">/* do something */</span> } absl::string_view a = <span class="st">&quot;...&quot;</span>; <span class="kw">if</span> (absl::string_view::npos != a.find(<span class="st">&quot;Hello World&quot;</span>)) { <span class="co">/* do something */</span> }</code></pre></div> <p>becomes</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::string s = <span class="st">&quot;...&quot;</span>; <span class="kw">if</span> (!absl::StrContains(s, <span class="st">&quot;Hello World&quot;</span>)) { <span class="co">/* do something */</span> } absl::string_view a = <span class="st">&quot;...&quot;</span>; <span class="kw">if</span> (absl::StrContains(a, <span class="st">&quot;Hello World&quot;</span>)) { <span class="co">/* do something */</span> }</code></pre></div> <h5 id="options-14">Options</h5> <p>StringLikeClasses</p> <p>Semicolon-separated list of names of string-like classes. By default includes ::std::basic_string, ::std::basic_string_view, and ::absl::string_view.</p> <p>IncludeStyle</p> <p>A string specifying which include-style is used, llvm or google. Default is llvm.</p> <p>AbseilStringsMatchHeader</p> <p>The location of Abseil’s strings/match.h. Defaults to absl/strings/match.h.</p> <p>(Clang-Tidy original name: abseil-string-find-str-contains)</p> + + + + Major + + + + + + + false + false + abseil-time-comparison + abseil + + true + Time Comparison + <p>Prefer comparisons in the absl::Time domain instead of the integer domain.</p> <p>N.B.: In cases where an absl::Time is being converted to an integer, alignment may occur. If the comparison depends on this alignment, doing the comparison in the absl::Time domain may yield a different result. In practice this is very rare, and still indicates a bug which should be fixed.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Original - Comparison in the integer domain</span> <span class="dt">int</span> x; absl::Time t; <span class="kw">if</span> (x &lt; absl::ToUnixSeconds(t)) ... <span class="co">// Suggested - Compare in the absl::Time domain instead</span> <span class="kw">if</span> (absl::FromUnixSeconds(x) &lt; t) ...</code></pre></div> <p>(Clang-Tidy original name: abseil-time-comparison)</p> + + + + Major + + + + + + + false + false + abseil-time-subtraction + abseil + + true + Time Subtraction + <p>Finds and fixes absl::Time subtraction expressions to do subtraction in the Time domain instead of the numeric domain.</p> <p>There are two cases of Time subtraction in which deduce additional type information:</p> <ul> <li>When the result is an absl::Duration and the first argument is an absl::Time.</li> <li>When the second argument is a absl::Time.</li> </ul> <p>In the first case, we must know the result of the operation, since without that the second operand could be either an absl::Time or an absl::Duration. In the second case, the first operand <em>must</em> be an absl::Time, because subtracting an absl::Time from an absl::Duration is not defined.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> x; absl::Time t; <span class="co">// Original - absl::Duration result and first operand is a absl::Time.</span> absl::Duration d = absl::Seconds(absl::ToUnixSeconds(t) - x); <span class="co">// Suggestion - Perform subtraction in the Time domain instead.</span> absl::Duration d = t - absl::FromUnixSeconds(x); <span class="co">// Original - Second operand is an absl::Time.</span> <span class="dt">int</span> i = x - absl::ToUnixSeconds(t); <span class="co">// Suggestion - Perform subtraction in the Time domain instead.</span> <span class="dt">int</span> i = absl::ToInt64Seconds(absl::FromUnixSeconds(x) - t);</code></pre></div> <p>(Clang-Tidy original name: abseil-time-subtraction)</p> + + + + Major + + + + + + + false + false + abseil-upgrade-duration-conversions + abseil + + true + Upgrade Duration Conversions + <p>Finds calls to absl::Duration arithmetic operators and factories whose argument needs an explicit cast to continue compiling after upcoming API changes.</p> <p>The operators <em>=, /=, </em>, and / for absl::Duration currently accept an argument of class type that is convertible to an arithmetic type. Such a call currently converts the value to an int64_t, even in a case such as std::atomic<float> that would result in lossy conversion.</p> <p>Additionally, the absl::Duration factory functions (absl::Hours, absl::Minutes, etc) currently accept an int64_t or a floating-point type. Similar to the arithmetic operators, calls with an argument of class type that is convertible to an arithmetic type go through the int64_t path.</p> <p>These operators and factories will be changed to only accept arithmetic types to prevent unintended behavior. After these changes are released, passing an argument of class type will no longer compile, even if the type is implicitly convertible to an arithmetic type.</p> <p>Here are example fixes created by this check:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::atomic&lt;<span class="dt">int</span>&gt; a; absl::Duration d = absl::Milliseconds(a); d *= a;</code></pre></div> <p>becomes</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::atomic&lt;<span class="dt">int</span>&gt; a; absl::Duration d = absl::Milliseconds(<span class="kw">static_cast</span>&lt;<span class="dt">int64_t</span>&gt;(a)); d *= <span class="kw">static_cast</span>&lt;<span class="dt">int64_t</span>&gt;(a);</code></pre></div> <p>Note that this check always adds a cast to int64_t in order to preserve the current behavior of user code. It is possible that this uncovers unintended behavior due to types implicitly convertible to a floating-point type.</p> <p>(Clang-Tidy original name: abseil-upgrade-duration-conversions)</p> + + + + Major + + + + + + + false + false + altera-kernel-name-restriction + altera + + true + Kernel Name Restriction + <p>Finds kernel files and include directives whose filename is kernel.cl, Verilog.cl, or VHDL.cl. The check is case insensitive.</p> <p>Such kernel file names cause the offline compiler to generate intermediate design files that have the same names as certain internal files, which leads to a compilation error.</p> <p>Based on the Guidelines for Naming the Kernel section in the <a href="https://www.intel.com/content/www/us/en/programmable/documentation/mwh1391807965224.html#ewa1412973930963">Intel FPGA SDK for OpenCL Pro Edition: Programming Guide</a>.</p> <p>(Clang-Tidy original name: altera-kernel-name-restriction)</p> + + + + Major + + + + + + + false + false + altera-struct-pack-align + altera + + true + Struct Pack Align + <p>Finds structs that are inefficiently packed or aligned, and recommends packing and/or aligning of said structs as needed.</p> <p>Structs that are not packed take up more space than they should, and accessing structs that are not well aligned is inefficient.</p> <p>Fix-its are provided to fix both of these issues by inserting and/or amending relevant struct attributes.</p> <p>Based on the <a href="https://www.altera.com/en_US/pdfs/literature/hb/opencl-sdk/aocl_optimization_guide.pdf">Altera SDK for OpenCL: Best Practices Guide</a>.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// The following struct is originally aligned to 4 bytes, and thus takes up</span> <span class="co">// 12 bytes of memory instead of 10. Packing the struct will make it use</span> <span class="co">// only 10 bytes of memory, and aligning it to 16 bytes will make it</span> <span class="co">// efficient to access.</span> <span class="kw">struct</span> example { <span class="dt">char</span> a; <span class="co">// 1 byte</span> <span class="dt">double</span> b; <span class="co">// 8 bytes</span> <span class="dt">char</span> c; <span class="co">// 1 byte</span> }; <span class="co">// The following struct is arranged in such a way that packing is not needed.</span> <span class="co">// However, it is aligned to 4 bytes instead of 8, and thus needs to be</span> <span class="co">// explicitly aligned.</span> <span class="kw">struct</span> implicitly_packed_example { <span class="dt">char</span> a; <span class="co">// 1 byte</span> <span class="dt">char</span> b; <span class="co">// 1 byte</span> <span class="dt">char</span> c; <span class="co">// 1 byte</span> <span class="dt">char</span> d; <span class="co">// 1 byte</span> <span class="dt">int</span> e; <span class="co">// 4 bytes</span> }; <span class="co">// The following struct is explicitly aligned and packed.</span> <span class="kw">struct</span> good_example { <span class="dt">char</span> a; <span class="co">// 1 byte</span> <span class="dt">double</span> b; <span class="co">// 8 bytes</span> <span class="dt">char</span> c; <span class="co">// 1 byte</span> } <span class="ot">__attribute__</span>((packed)) <span class="ot">__attribute__</span>((aligned(<span class="dv">16</span>)); <span class="co">// Explicitly aligning a struct to the wrong value will result in a warning.</span> <span class="co">// The following example should be aligned to 16 bytes, not 32.</span> <span class="kw">struct</span> badly_aligned_example { <span class="dt">char</span> a; <span class="co">// 1 byte</span> <span class="dt">double</span> b; <span class="co">// 8 bytes</span> <span class="dt">char</span> c; <span class="co">// 1 byte</span> } <span class="ot">__attribute__</span>((packed)) <span class="ot">__attribute__</span>((aligned(<span class="dv">32</span>)));</code></pre></div> <p>(Clang-Tidy original name: altera-struct-pack-align)</p> + + + + Major + + + + + + + false + false + altera-single-work-item-barrier + altera + + true + Single Work Item Barrier + <p>Finds OpenCL kernel functions that call a barrier function but do not call an ID function (get_local_id, get_local_id, get_group_id, or get_local_linear_id).</p> <p>These kernels may be viable single work-item kernels, but will be forced to execute as NDRange kernels if using a newer version of the Altera Offline Compiler (&gt;= v17.01).</p> <p>If using an older version of the Altera Offline Compiler, these kernel functions will be treated as single work-item kernels, which could be inefficient or lead to errors if NDRange semantics were intended.</p> <p>Based on the <a href="https://www.altera.com/en_US/pdfs/literature/hb/opencl-sdk/aocl_optimization_guide.pdf">Altera SDK for OpenCL: Best Practices Guide</a>.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// error: function calls barrier but does not call an ID function.</span> <span class="dt">void</span> __kernel barrier_no_id(__global <span class="dt">int</span> * foo, <span class="dt">int</span> size) { <span class="kw">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; <span class="dv">100</span>; i++) { foo[i] += <span class="dv">5</span>; } barrier(CLK_GLOBAL_MEM_FENCE); } <span class="co">// ok: function calls barrier and an ID function.</span> <span class="dt">void</span> __kernel barrier_with_id(__global <span class="dt">int</span> * foo, <span class="dt">int</span> size) { <span class="kw">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; <span class="dv">100</span>; i++) { <span class="dt">int</span> tid = get_global_id(<span class="dv">0</span>); foo[tid] += <span class="dv">5</span>; } barrier(CLK_GLOBAL_MEM_FENCE); } <span class="co">// ok with AOC Version 17.01: the reqd_work_group_size turns this into</span> <span class="co">// an NDRange.</span> <span class="ot">__attribute__</span>((reqd_work_group_size(<span class="dv">2</span>,<span class="dv">2</span>,<span class="dv">2</span>))) <span class="dt">void</span> __kernel barrier_with_id(__global <span class="dt">int</span> * foo, <span class="dt">int</span> size) { <span class="kw">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; <span class="dv">100</span>; i++) { foo[tid] += <span class="dv">5</span>; } barrier(CLK_GLOBAL_MEM_FENCE); }</code></pre></div> <h5 id="options-44">Options</h5> <p>AOCVersion</p> <p>Defines the version of the Altera Offline Compiler. Defaults to 1600 (corresponding to version 16.00).</p> <p>(Clang-Tidy original name: altera-single-work-item-barrier)</p> + + + + Major + + + + + + + false + false + android-cloexec-accept4 + android + + true + Cloexec Accept4 + <p>accept4() should include SOCK_CLOEXEC in its type argument to avoid the file descriptor leakage. Without this flag, an opened sensitive file would remain open across a fork+exec to a lower-privileged SELinux domain.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">accept4(sockfd, addr, addrlen, SOCK_NONBLOCK); <span class="co">// becomes</span> accept4(sockfd, addr, addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);</code></pre></div> <p>(Clang-Tidy original name: android-cloexec-accept4)</p> + + + + Major + + + + + + + false + false + android-cloexec-accept + android + + true + Cloexec Accept + <p>The usage of accept() is not recommended, it’s better to use accept4(). Without this flag, an opened sensitive file descriptor would remain open across a fork+exec to a lower-privileged SELinux domain.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">accept(sockfd, addr, addrlen); <span class="co">// becomes</span> accept4(sockfd, addr, addrlen, SOCK_CLOEXEC);</code></pre></div> <p>(Clang-Tidy original name: android-cloexec-accept)</p> + + + + Major + + + + + + + false + false + android-cloexec-creat + android + + true + Cloexec Creat + <p>The usage of creat() is not recommended, it’s better to use open().</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> fd = creat(path, mode); <span class="co">// becomes</span> <span class="dt">int</span> fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);</code></pre></div> <p>(Clang-Tidy original name: android-cloexec-creat)</p> + + + + Major + + + + + + + false + false + android-cloexec-dup + android + + true + Cloexec Dup + <p>The usage of dup() is not recommended, it’s better to use fcntl(), which can set the close-on-exec flag. Otherwise, an opened sensitive file would remain open across a fork+exec to a lower-privileged SELinux domain.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> fd = dup(oldfd); <span class="co">// becomes</span> <span class="dt">int</span> fd = fcntl(oldfd, F_DUPFD_CLOEXEC);</code></pre></div> <p>(Clang-Tidy original name: android-cloexec-dup)</p> + + + + Major + + + + + + + false + false + android-cloexec-epoll-create1 + android + + true + Cloexec Epoll Create1 + <p>epoll_create1() should include EPOLL_CLOEXEC in its type argument to avoid the file descriptor leakage. Without this flag, an opened sensitive file would remain open across a fork+exec to a lower-privileged SELinux domain.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">epoll_create1(<span class="dv">0</span>); <span class="co">// becomes</span> epoll_create1(EPOLL_CLOEXEC);</code></pre></div> <p>(Clang-Tidy original name: android-cloexec-epoll-create1)</p> + + + + Major + + + + + + + false + false + android-cloexec-epoll-create + android + + true + Cloexec Epoll Create + <p>The usage of epoll_create() is not recommended, it’s better to use epoll_create1(), which allows close-on-exec.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">epoll_create(size); <span class="co">// becomes</span> epoll_create1(EPOLL_CLOEXEC);</code></pre></div> <p>(Clang-Tidy original name: android-cloexec-epoll-create)</p> + + + + Major + + + + + + + false + false + android-cloexec-fopen + android + + true + Cloexec Fopen + <p>fopen() should include e in their mode string; so re would be valid. This is equivalent to having set FD_CLOEXEC on that descriptor.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">fopen(<span class="st">&quot;fn&quot;</span>, <span class="st">&quot;r&quot;</span>); <span class="co">// becomes</span> fopen(<span class="st">&quot;fn&quot;</span>, <span class="st">&quot;re&quot;</span>);</code></pre></div> <p>(Clang-Tidy original name: android-cloexec-fopen)</p> + + + + Major + + + + + + + false + false + android-cloexec-inotify-init1 + android + + true + Cloexec Inotify Init1 + <p>inotify_init1() should include IN_CLOEXEC in its type argument to avoid the file descriptor leakage. Without this flag, an opened sensitive file would remain open across a fork+exec to a lower-privileged SELinux domain.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">inotify_init1(IN_NONBLOCK); <span class="co">// becomes</span> inotify_init1(IN_NONBLOCK | IN_CLOEXEC);</code></pre></div> <p>(Clang-Tidy original name: android-cloexec-inotify-init1)</p> + + + + Major + + + + + + + false + false + android-cloexec-inotify-init + android + + true + Cloexec Inotify Init + <p>The usage of inotify_init() is not recommended, it’s better to use inotify_init1().</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">inotify_init(); <span class="co">// becomes</span> inotify_init1(IN_CLOEXEC);</code></pre></div> <p>(Clang-Tidy original name: android-cloexec-inotify-init)</p> + + + + Major + + + + + + + false + false + android-comparison-in-temp-failure-retry + android + + true + Comparison In Temp Failure Retry + <p>Diagnoses comparisons that appear to be incorrectly placed in the argument to the TEMP_FAILURE_RETRY macro. Having such a use is incorrect in the vast majority of cases, and will often silently defeat the purpose of the TEMP_FAILURE_RETRY macro.</p> <p>For context, TEMP_FAILURE_RETRY is <a href="https://www.gnu.org/software/libc/manual/html_node/Interrupted-Primitives.html">a convenience macro</a> provided by both glibc and Bionic. Its purpose is to repeatedly run a syscall until it either succeeds, or fails for reasons other than being interrupted.</p> <p>Example buggy usage looks like:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">char</span> cs[<span class="dv">1</span>]; <span class="kw">while</span> (TEMP_FAILURE_RETRY(read(STDIN_FILENO, cs, <span class="kw">sizeof</span>(cs)) != <span class="dv">0</span>)) { <span class="co">// Do something with cs.</span> }</code></pre></div> <p>Because TEMP_FAILURE_RETRY will check for whether the result <em>of the comparison</em> is -1, and retry if so.</p> <p>If you encounter this, the fix is simple: lift the comparison out of the TEMP_FAILURE_RETRY argument, like so:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">char</span> cs[<span class="dv">1</span>]; <span class="kw">while</span> (TEMP_FAILURE_RETRY(read(STDIN_FILENO, cs, <span class="kw">sizeof</span>(cs))) != <span class="dv">0</span>) { <span class="co">// Do something with cs.</span> }</code></pre></div> <h5 id="options-50">Options</h5> <p>RetryMacros</p> <p>A comma-separated list of the names of retry macros to be checked.</p> <p>(Clang-Tidy original name: android-comparison-in-temp-failure-retry)</p> + + + + Major + + + + + + + false + false + android-cloexec-memfd-create + android + + true + Cloexec Memfd Create + <p>memfd_create() should include MFD_CLOEXEC in its type argument to avoid the file descriptor leakage. Without this flag, an opened sensitive file would remain open across a fork+exec to a lower-privileged SELinux domain.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">memfd_create(name, MFD_ALLOW_SEALING); <span class="co">// becomes</span> memfd_create(name, MFD_ALLOW_SEALING | MFD_CLOEXEC);</code></pre></div> <p>(Clang-Tidy original name: android-cloexec-memfd-create)</p> + + + + Major + + + + + + + false + false + android-cloexec-open + android + + true + Cloexec Open + <p>A common source of security bugs is code that opens a file without using the O_CLOEXEC flag. Without that flag, an opened sensitive file would remain open across a fork+exec to a lower-privileged SELinux domain, leaking that sensitive data. Open-like functions including open(), openat(), and open64() should include O_CLOEXEC in their flags argument.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">open(<span class="st">&quot;filename&quot;</span>, O_RDWR); open64(<span class="st">&quot;filename&quot;</span>, O_RDWR); openat(<span class="dv">0</span>, <span class="st">&quot;filename&quot;</span>, O_RDWR); <span class="co">// becomes</span> open(<span class="st">&quot;filename&quot;</span>, O_RDWR | O_CLOEXEC); open64(<span class="st">&quot;filename&quot;</span>, O_RDWR | O_CLOEXEC); openat(<span class="dv">0</span>, <span class="st">&quot;filename&quot;</span>, O_RDWR | O_CLOEXEC);</code></pre></div> <p>(Clang-Tidy original name: android-cloexec-open)</p> + + + + Major + + + + + + + false + false + android-cloexec-pipe2 + android + + true + Cloexec Pipe2 + <p>This checks ensures that pipe2() is called with the O_CLOEXEC flag. The check also adds the O_CLOEXEC flag that marks the file descriptor to be closed in child processes. Without this flag a sensitive file descriptor can be leaked to a child process, potentially into a lower-privileged SELinux domain.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">pipe2(pipefd, O_NONBLOCK);</code></pre></div> <p>Suggested replacement:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">pipe2(pipefd, O_NONBLOCK | O_CLOEXEC);</code></pre></div> <p>(Clang-Tidy original name: android-cloexec-pipe2)</p> + + + + Major + + + + + + + false + false + android-cloexec-pipe + android + + true + Cloexec Pipe + <p>This check detects usage of pipe(). Using pipe() is not recommended, pipe2() is the suggested replacement. The check also adds the O_CLOEXEC flag that marks the file descriptor to be closed in child processes. Without this flag a sensitive file descriptor can be leaked to a child process, potentially into a lower-privileged SELinux domain.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">pipe(pipefd);</code></pre></div> <p>Suggested replacement:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">pipe2(pipefd, O_CLOEXEC);</code></pre></div> <p>(Clang-Tidy original name: android-cloexec-pipe)</p> + + + + Major + + + + + + + false + false + android-cloexec-socket + android + + true + Cloexec Socket + <p>socket() should include SOCK_CLOEXEC in its type argument to avoid the file descriptor leakage. Without this flag, an opened sensitive file would remain open across a fork+exec to a lower-privileged SELinux domain.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">socket(domain, type, SOCK_STREAM); <span class="co">// becomes</span> socket(domain, type, SOCK_STREAM | SOCK_CLOEXEC);</code></pre></div> <p>(Clang-Tidy original name: android-cloexec-socket)</p> + + + + Major + + + + + + + true + false + boost-use-to-string + boost + + true + Use To String + <p>This check finds conversion from integer type like int to std::string or std::wstring using boost::lexical_cast, and replace it with calls to std::to_string and std::to_wstring.</p> <p>It doesn’t replace conversion from floating points despite the to_string overloads, because it would change the behaviour.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">auto</span> str = boost::lexical_cast&lt;std::string&gt;(<span class="dv">42</span>); <span class="kw">auto</span> wstr = boost::lexical_cast&lt;std::wstring&gt;(<span class="dv">2137LL</span>); <span class="co">// Will be changed to</span> <span class="kw">auto</span> str = std::to_string(<span class="dv">42</span>); <span class="kw">auto</span> wstr = std::to_wstring(<span class="dv">2137LL</span>);</code></pre></div> <p>(Clang-Tidy original name: boost-use-to-string)</p> + + + + Major + + + + + + + true + false + bugprone-argument-comment + bugprone + + true + Argument Comment + <p>Checks that argument comments match parameter names.</p> <p>The check understands argument comments in the form /<em>parameter_name=</em>/ that are placed right before the argument.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> f(<span class="dt">bool</span> foo); ... f(<span class="co">/*bar=*/</span><span class="kw">true</span>); <span class="co">// warning: argument name &#39;bar&#39; in comment does not match parameter name &#39;foo&#39;</span></code></pre></div> <p>The check tries to detect typos and suggest automated fixes for them.</p> <h5 id="options-49">Options</h5> <p>StrictMode</p> <p>When false (default value), the check will ignore leading and trailing underscores and case when comparing names – otherwise they are taken into account.</p> <p>IgnoreSingleArgument</p> <p>When true, the check will ignore the single argument.</p> <p>CommentBoolLiterals</p> <p>When true, the check will add argument comments in the format /<em>ParameterName=</em>/ right before the boolean literal argument.</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo(<span class="dt">bool</span> TurnKey, <span class="dt">bool</span> PressButton); foo(<span class="kw">true</span>, <span class="kw">false</span>);</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo(<span class="dt">bool</span> TurnKey, <span class="dt">bool</span> PressButton); foo(<span class="co">/*TurnKey=*/</span><span class="kw">true</span>, <span class="co">/*PressButton=*/</span><span class="kw">false</span>);</code></pre></div> <p>CommentIntegerLiterals</p> <p>When true, the check will add argument comments in the format /<em>ParameterName=</em>/ right before the integer literal argument.</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo(<span class="dt">int</span> MeaningOfLife); foo(<span class="dv">42</span>);</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo(<span class="dt">int</span> MeaningOfLife); foo(<span class="co">/*MeaningOfLife=*/</span><span class="dv">42</span>);</code></pre></div> <p>CommentFloatLiterals</p> <p>When true, the check will add argument comments in the format /<em>ParameterName=</em>/ right before the float/double literal argument.</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo(<span class="dt">float</span> Pi); foo(<span class="fl">3.14159</span>);</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo(<span class="dt">float</span> Pi); foo(<span class="co">/*Pi=*/</span><span class="fl">3.14159</span>);</code></pre></div> <p>CommentStringLiterals</p> <p>When true, the check will add argument comments in the format /<em>ParameterName=</em>/ right before the string literal argument.</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo(<span class="dt">const</span> <span class="dt">char</span> *String); <span class="dt">void</span> foo(<span class="dt">const</span> <span class="dt">wchar_t</span> *WideString); foo(<span class="st">&quot;Hello World&quot;</span>); foo(<span class="st">L&quot;Hello World&quot;</span>);</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo(<span class="dt">const</span> <span class="dt">char</span> *String); <span class="dt">void</span> foo(<span class="dt">const</span> <span class="dt">wchar_t</span> *WideString); foo(<span class="co">/*String=*/</span><span class="st">&quot;Hello World&quot;</span>); foo(<span class="co">/*WideString=*/</span><span class="st">L&quot;Hello World&quot;</span>);</code></pre></div> <p>CommentCharacterLiterals</p> <p>When true, the check will add argument comments in the format /<em>ParameterName=</em>/ right before the character literal argument.</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo(<span class="dt">char</span> *Character); foo(<span class="st">&#39;A&#39;</span>);</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo(<span class="dt">char</span> *Character); foo(<span class="co">/*Character=*/</span><span class="st">&#39;A&#39;</span>);</code></pre></div> <p>CommentUserDefinedLiterals</p> <p>When true, the check will add argument comments in the format /<em>ParameterName=</em>/ right before the user defined literal argument.</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo(<span class="dt">double</span> Distance); <span class="dt">double</span> <span class="kw">operator</span><span class="st">&quot;&quot;</span> _km(<span class="dt">long</span> <span class="dt">double</span>); foo(<span class="fl">402.0</span>_km);</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo(<span class="dt">double</span> Distance); <span class="dt">double</span> <span class="kw">operator</span><span class="st">&quot;&quot;</span> _km(<span class="dt">long</span> <span class="dt">double</span>); foo(<span class="co">/*Distance=*/</span><span class="fl">402.0</span>_km);</code></pre></div> <p>CommentNullPtrs</p> <p>When true, the check will add argument comments in the format /<em>ParameterName=</em>/ right before the nullptr literal argument.</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo(A* Value); foo(<span class="kw">nullptr</span>);</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo(A* Value); foo(<span class="co">/*Value=*/</span><span class="kw">nullptr</span>);</code></pre></div> <p>(Clang-Tidy original name: bugprone-argument-comment)</p> + + + + Major + + + + + + + true + false + bugprone-assert-side-effect + bugprone + + true + Assert Side Effect + <p>Finds assert() with side effect.</p> <p>The condition of assert() is evaluated only in debug builds so a condition with side effect can cause different behavior in debug / release builds.</p> <h5 id="options-16">Options</h5> <p>AssertMacros</p> <p>A comma-separated list of the names of assert macros to be checked.</p> <p>CheckFunctionCalls</p> <p>Whether to treat non-const member and non-member functions as they produce side effects. Disabled by default because it can increase the number of false positive warnings.</p> <p>(Clang-Tidy original name: bugprone-assert-side-effect)</p> + + + + Major + + + + + + + true + false + bugprone-branch-clone + bugprone + + true + Branch Clone + <p>Checks for repeated branches in if/else if/else chains, consecutive repeated branches in switch statements and identical true and false branches in conditional operators.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">if</span> (test_value(x)) { y++; do_something(x, y); } <span class="kw">else</span> { y++; do_something(x, y); }</code></pre></div> <p>In this simple example (which could arise e.g. as a copy-paste error) the then and else branches are identical and the code is equivalent the following shorter and cleaner code:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">test_value(x); <span class="co">// can be omitted unless it has side effects</span> y++; do_something(x, y);</code></pre></div> <p>If this is the intended behavior, then there is no reason to use a conditional statement; otherwise the issue can be solved by fixing the branch that is handled incorrectly.</p> <p>The check also detects repeated branches in longer if/else if/else chains where it would be even harder to notice the problem.</p> <p>In switch statements the check only reports repeated branches when they are consecutive, because it is relatively common that the case: labels have some natural ordering and rearranging them would decrease the readability of the code. For example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">switch</span> (ch) { <span class="kw">case</span> <span class="st">&#39;a&#39;</span>: <span class="kw">return</span> <span class="dv">10</span>; <span class="kw">case</span> <span class="st">&#39;A&#39;</span>: <span class="kw">return</span> <span class="dv">10</span>; <span class="kw">case</span> <span class="st">&#39;b&#39;</span>: <span class="kw">return</span> <span class="dv">11</span>; <span class="kw">case</span> <span class="st">&#39;B&#39;</span>: <span class="kw">return</span> <span class="dv">11</span>; <span class="kw">default</span>: <span class="kw">return</span> <span class="dv">10</span>; }</code></pre></div> <p>Here the check reports that the 'a' and 'A' branches are identical (and that the 'b' and 'B' branches are also identical), but does not report that the default: branch is also identical to the first two branches. If this is indeed the correct behavior, then it could be implemented as:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">switch</span> (ch) { <span class="kw">case</span> <span class="st">&#39;a&#39;</span>: <span class="kw">case</span> <span class="st">&#39;A&#39;</span>: <span class="kw">return</span> <span class="dv">10</span>; <span class="kw">case</span> <span class="st">&#39;b&#39;</span>: <span class="kw">case</span> <span class="st">&#39;B&#39;</span>: <span class="kw">return</span> <span class="dv">11</span>; <span class="kw">default</span>: <span class="kw">return</span> <span class="dv">10</span>; }</code></pre></div> <p>Here the check does not warn for the repeated return 10;, which is good if we want to preserve that 'a' is before 'b' and default: is the last branch.</p> <p>Finally, the check also examines conditional operators and reports code like:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">return</span> test_value(x) ? x : x;</code></pre></div> <p>Unlike if statements, the check does not detect chains of conditional operators.</p> <p>Note: This check also reports situations where branches become identical only after preprocession.</p> <p>(Clang-Tidy original name: bugprone-branch-clone)</p> + + + + Major + + + + + + + true + false + bugprone-bool-pointer-implicit-conversion + bugprone + + true + Bool Pointer Implicit Conversion + <p>Checks for conditions based on implicit conversion from a bool pointer to bool.</p> <p>Example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">bool</span> *p; <span class="kw">if</span> (p) { <span class="co">// Never used in a pointer-specific way.</span> }</code></pre></div> <p>(Clang-Tidy original name: bugprone-bool-pointer-implicit-conversion)</p> + + + + Major + + + + + + + true + false + bugprone-bad-signal-to-kill-thread + bugprone + + true + Bad Signal To Kill Thread + <p>Finds pthread_kill function calls when a thread is terminated by raising SIGTERM signal and the signal kills the entire process, not just the individual thread. Use any signal except SIGTERM.</p> <p>This check corresponds to the CERT C Coding Standard rule <a href="https://wiki.sei.cmu.edu/confluence/display/c/POS44-C.+Do+not+use+signals+to+terminate+threads">POS44-C. Do not use signals to terminate threads</a>.</p> <p>(Clang-Tidy original name: bugprone-bad-signal-to-kill-thread)</p> + + + + Major + + + + + + + true + false + bugprone-copy-constructor-init + bugprone + + true + Copy Constructor Init + <p>Finds copy constructors where the constructor doesn’t call the copy constructor of the base class.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Copyable { <span class="kw">public</span>: Copyable() = <span class="kw">default</span>; Copyable(<span class="dt">const</span> Copyable &amp;) = <span class="kw">default</span>; }; <span class="kw">class</span> X2 : <span class="kw">public</span> Copyable { X2(<span class="dt">const</span> X2 &amp;other) {} <span class="co">// Copyable(other) is missing</span> };</code></pre></div> <p>Also finds copy constructors where the constructor of the base class don’t have parameter.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> X4 : <span class="kw">public</span> Copyable { X4(<span class="dt">const</span> X4 &amp;other) : Copyable() {} <span class="co">// other is missing</span> };</code></pre></div> <p>The check also suggests a fix-its in some cases.</p> <p>(Clang-Tidy original name: bugprone-copy-constructor-init)</p> + + + + Major + + + + + + + true + false + bugprone-dangling-handle + bugprone + + true + Dangling Handle + <p>Detect dangling references in value handles like std::experimental::string_view. These dangling references can be a result of constructing handles from temporary values, where the temporary is destroyed soon after the handle is created.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">string_view View = string(); <span class="co">// View will dangle.</span> string A; View = A + <span class="st">&quot;A&quot;</span>; <span class="co">// still dangle.</span> vector&lt;string_view&gt; V; V.push_back(string()); <span class="co">// V[0] is dangling.</span> V.resize(<span class="dv">3</span>, string()); <span class="co">// V[1] and V[2] will also dangle.</span> string_view f() { <span class="co">// All these return values will dangle.</span> <span class="kw">return</span> string(); string S; <span class="kw">return</span> S; <span class="dt">char</span> Array[<span class="dv">10</span>]{}; <span class="kw">return</span> Array; }</code></pre></div> <h5 id="options-4">Options</h5> <p>HandleClasses</p> <p>A semicolon-separated list of class names that should be treated as handles. By default only std::experimental::basic_string_view is considered.</p> <p>(Clang-Tidy original name: bugprone-dangling-handle)</p> + + + + Major + + + + + + + true + false + bugprone-dynamic-static-initializers + bugprone + + true + Dynamic Static Initializers + <p>Finds instances of static variables that are dynamically initialized in header files.</p> <p>This can pose problems in certain multithreaded contexts. For example, when disabling compiler generated synchronization instructions for static variables initialized at runtime (e.g. by -fno-threadsafe-statics), even if a particular project takes the necessary precautions to prevent race conditions during initialization by providing their own synchronization, header files included from other projects may not. Therefore, such a check is helpful for ensuring that disabling compiler generated synchronization for static variable initialization will not cause problems.</p> <p>Consider the following code:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> foo() { <span class="dt">static</span> <span class="dt">int</span> k = bar(); <span class="kw">return</span> k; }</code></pre></div> <p>When synchronization of static initialization is disabled, if two threads both call foo for the first time, there is the possibility that k will be double initialized, creating a race condition.</p> <p>(Clang-Tidy original name: bugprone-dynamic-static-initializers)</p> + + + + Major + + + + + + + true + false + bugprone-exception-escape + bugprone + + true + Exception Escape + <p>Finds functions which may throw an exception directly or indirectly, but they should not. The functions which should not throw exceptions are the following:</p> <ul> <li>Destructors</li> <li>Move constructors</li> <li>Move assignment operators</li> <li>The main() functions</li> <li>swap() functions</li> <li>Functions marked with throw() or noexcept</li> <li>Other functions given as option</li> </ul> <p>A destructor throwing an exception may result in undefined behavior, resource leaks or unexpected termination of the program. Throwing move constructor or move assignment also may result in undefined behavior or resource leak. The swap() operations expected to be non throwing most of the cases and they are always possible to implement in a non throwing way. Non throwing swap() operations are also used to create move operations. A throwing main() function also results in unexpected termination.</p> <p>WARNING! This check may be expensive on large source files.</p> <h5 id="options-42">Options</h5> <p>FunctionsThatShouldNotThrow</p> <p>Comma separated list containing function names which should not throw. An example value for this parameter can be WinMain which adds function WinMain() in the Windows API to the list of the functions which should not throw. Default value is an empty string.</p> <p>IgnoredExceptions</p> <p>Comma separated list containing type names which are not counted as thrown exceptions in the check. Default value is an empty string.</p> <p>(Clang-Tidy original name: bugprone-exception-escape)</p> + + + + Major + + + + + + + true + false + bugprone-forward-declaration-namespace + bugprone + + true + Forward Declaration Namespace + <p>Checks if an unused forward declaration is in a wrong namespace.</p> <p>The check inspects all unused forward declarations and checks if there is any declaration/definition with the same name existing, which could indicate that the forward declaration is in a potentially wrong namespace.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">namespace</span> na { <span class="kw">struct</span> A; } <span class="kw">namespace</span> nb { <span class="kw">struct</span> A {}; } nb::A a; <span class="co">// warning : no definition found for &#39;A&#39;, but a definition with the same name</span> <span class="co">// &#39;A&#39; found in another namespace &#39;nb::&#39;</span></code></pre></div> <p>This check can only generate warnings, but it can’t suggest a fix at this point.</p> <p>(Clang-Tidy original name: bugprone-forward-declaration-namespace)</p> + + + + Major + + + + + + + true + false + bugprone-fold-init-type + bugprone + + true + Fold Init Type + <p>The check flags type mismatches in <a href="https://en.wikipedia.org/wiki/Fold_(higher-order_function)">folds</a> like std::accumulate that might result in loss of precision. std::accumulate folds an input range into an initial value using the type of the latter, with operator+ by default. This can cause loss of precision through:</p> <ul> <li>Truncation: The following code uses a floating point range and an int initial value, so trucation will happen at every application of operator+ and the result will be 0, which might not be what the user expected.</li> </ul> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">auto</span> a = {<span class="fl">0.5f</span>, <span class="fl">0.5f</span>, <span class="fl">0.5f</span>, <span class="fl">0.5f</span>}; <span class="kw">return</span> std::accumulate(std::begin(a), std::end(a), <span class="dv">0</span>);</code></pre></div> <ul> <li>Overflow: The following code also returns 0.</li> </ul> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">auto</span> a = {<span class="dv">65536LL</span> * <span class="dv">65536</span> * <span class="dv">65536</span>}; <span class="kw">return</span> std::accumulate(std::begin(a), std::end(a), <span class="dv">0</span>);</code></pre></div> <p>(Clang-Tidy original name: bugprone-fold-init-type)</p> + + + + Major + + + + + + + true + false + bugprone-forwarding-reference-overload + bugprone + + true + Forwarding Reference Overload + <p>The check looks for perfect forwarding constructors that can hide copy or move constructors. If a non const lvalue reference is passed to the constructor, the forwarding reference parameter will be a better match than the const reference parameter of the copy constructor, so the perfect forwarding constructor will be called, which can be confusing. For detailed description of this issue see: Scott Meyers, Effective Modern C++, Item 26.</p> <p>Consider the following example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Person { <span class="kw">public</span>: <span class="co">// C1: perfect forwarding ctor</span> <span class="kw">template</span>&lt;<span class="kw">typename</span> T&gt; <span class="kw">explicit</span> Person(T&amp;&amp; n) {} <span class="co">// C2: perfect forwarding ctor with parameter default value</span> <span class="kw">template</span>&lt;<span class="kw">typename</span> T&gt; <span class="kw">explicit</span> Person(T&amp;&amp; n, <span class="dt">int</span> x = <span class="dv">1</span>) {} <span class="co">// C3: perfect forwarding ctor guarded with enable_if</span> <span class="kw">template</span>&lt;<span class="kw">typename</span> T, <span class="kw">typename</span> X = enable_if_t&lt;is_special&lt;T&gt;,<span class="dt">void</span>&gt;&gt; <span class="kw">explicit</span> Person(T&amp;&amp; n) {} <span class="co">// (possibly compiler generated) copy ctor</span> Person(<span class="dt">const</span> Person&amp; rhs); };</code></pre></div> <p>The check warns for constructors C1 and C2, because those can hide copy and move constructors. We suppress warnings if the copy and the move constructors are both disabled (deleted or private), because there is nothing the perfect forwarding constructor could hide in this case. We also suppress warnings for constructors like C3 that are guarded with an enable_if, assuming the programmer was aware of the possible hiding.</p> <h5 id="background">Background</h5> <p>For deciding whether a constructor is guarded with enable_if, we consider the default values of the type parameters and the types of the constructor parameters. If any part of these types is std::enable_if or std::enable_if_t, we assume the constructor is guarded.</p> <p>(Clang-Tidy original name: bugprone-forwarding-reference-overload)</p> + + + + Major + + + + + + + true + false + bugprone-integer-division + bugprone + + true + Integer Division + <p>Finds cases where integer division in a floating point context is likely to cause unintended loss of precision.</p> <p>No reports are made if divisions are part of the following expressions:</p> <ul> <li>operands of operators expecting integral or bool types,</li> <li>call expressions of integral or bool types, and</li> <li>explicit cast expressions to integral or bool types,</li> </ul> <p>as these are interpreted as signs of deliberateness from the programmer.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">float</span> floatFunc(<span class="dt">float</span>); <span class="dt">int</span> intFunc(<span class="dt">int</span>); <span class="dt">double</span> d; <span class="dt">int</span> i = <span class="dv">42</span>; <span class="co">// Warn, floating-point values expected.</span> d = <span class="dv">32</span> * <span class="dv">8</span> / (<span class="dv">2</span> + i); d = <span class="dv">8</span> * floatFunc(<span class="dv">1</span> + <span class="dv">7</span> / <span class="dv">2</span>); d = i / (<span class="dv">1</span> &lt;&lt; <span class="dv">4</span>); <span class="co">// OK, no integer division.</span> d = <span class="dv">32</span> * <span class="fl">8.0</span> / (<span class="dv">2</span> + i); d = <span class="dv">8</span> * floatFunc(<span class="dv">1</span> + <span class="fl">7.0</span> / <span class="dv">2</span>); d = (<span class="dt">double</span>)i / (<span class="dv">1</span> &lt;&lt; <span class="dv">4</span>); <span class="co">// OK, there are signs of deliberateness.</span> d = <span class="dv">1</span> &lt;&lt; (i / <span class="dv">2</span>); d = <span class="dv">9</span> + intFunc(<span class="dv">6</span> * i / <span class="dv">32</span>); d = (<span class="dt">int</span>)(i / <span class="dv">32</span>) - <span class="dv">8</span>;</code></pre></div> <p>(Clang-Tidy original name: bugprone-integer-division)</p> + + + + Major + + + + + + + true + false + bugprone-inaccurate-erase + bugprone + + true + Inaccurate Erase + <p>Checks for inaccurate use of the erase() method.</p> <p>Algorithms like remove() do not actually remove any element from the container but return an iterator to the first redundant element at the end of the container. These redundant elements must be removed using the erase() method. This check warns when not all of the elements will be removed due to using an inappropriate overload.</p> <p>For example, the following code erases only one element:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::vector&lt;<span class="dt">int</span>&gt; xs; ... xs.erase(std::remove(xs.begin(), xs.end(), <span class="dv">10</span>));</code></pre></div> <p>Call the two-argument overload of erase() to remove the subrange:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::vector&lt;<span class="dt">int</span>&gt; xs; ... xs.erase(std::remove(xs.begin(), xs.end(), <span class="dv">10</span>), xs.end());</code></pre></div> <p>(Clang-Tidy original name: bugprone-inaccurate-erase)</p> + + + + Major + + + + + + + true + false + bugprone-infinite-loop + bugprone + + true + Infinite Loop + <p>Finds obvious infinite loops (loops where the condition variable is not changed at all).</p> <p>Finding infinite loops is well-known to be impossible (halting problem). However, it is possible to detect some obvious infinite loops, for example, if the loop condition is not changed. This check detects such loops. A loop is considered infinite if it does not have any loop exit statement (break, continue, goto, return, throw or a call to a function called as [[noreturn]]) and all of the following conditions hold for every variable in the condition:</p> <ul> <li>It is a local variable.</li> <li>It has no reference or pointer aliases.</li> <li>It is not a structure or class member.</li> </ul> <p>Furthermore, the condition must not contain a function call to consider the loop infinite since functions may return different values for different calls.</p> <p>For example, the following loop is considered infinite i is not changed in the body:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> i = <span class="dv">0</span>, j = <span class="dv">0</span>; <span class="kw">while</span> (i &lt; <span class="dv">10</span>) { ++j; }</code></pre></div> <p>(Clang-Tidy original name: bugprone-infinite-loop)</p> + + + + Major + + + + + + + true + false + bugprone-incorrect-roundings + bugprone + + true + Incorrect Roundings + <p>Checks the usage of patterns known to produce incorrect rounding. Programmers often use:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">(<span class="dt">int</span>)(double_expression + <span class="fl">0.5</span>)</code></pre></div> <p>to round the double expression to an integer. The problem with this:</p> <ol style="list-style-type: decimal"> <li>It is unnecessarily slow.</li> <li>It is incorrect. The number 0.499999975 (smallest representable float number below 0.5) rounds to 1.0. Even worse behavior for negative numbers where both -0.5f and -1.4f both round to 0.0.</li> </ol> <p>(Clang-Tidy original name: bugprone-incorrect-roundings)</p> + + + + Major + + + + + + + true + false + bugprone-lambda-function-name + bugprone + + true + Lambda Function Name + <p>Checks for attempts to get the name of a function from within a lambda expression. The name of a lambda is always something like operator(), which is almost never what was intended.</p> <p>Example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> FancyFunction() { [] { printf(<span class="st">&quot;Called from </span><span class="ch">%s\n</span><span class="st">&quot;</span>, <span class="ot">__func__</span>); }(); [] { printf(<span class="st">&quot;Now called from </span><span class="ch">%s\n</span><span class="st">&quot;</span>, <span class="ot">__FUNCTION__</span>); }(); }</code></pre></div> <p>Output:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">Called from <span class="kw">operator</span>() Now called from <span class="kw">operator</span>()</code></pre></div> <p>Likely intended output:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">Called from FancyFunction Now called from FancyFunction</code></pre></div> <p>(Clang-Tidy original name: bugprone-lambda-function-name)</p> + + + + Major + + + + + + + true + false + bugprone-move-forwarding-reference + bugprone + + true + Move Forwarding Reference + <p>Warns if std::move is called on a forwarding reference, for example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">template</span> &lt;<span class="kw">typename</span> T&gt; <span class="dt">void</span> foo(T&amp;&amp; t) { bar(std::move(t)); }</code></pre></div> <p><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4164.pdf">Forwarding references</a> should typically be passed to std::forward instead of std::move, and this is the fix that will be suggested.</p> <p>(A forwarding reference is an rvalue reference of a type that is a deduced function template argument.)</p> <p>In this example, the suggested fix would be</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">bar(std::forward&lt;T&gt;(t));</code></pre></div> <h5 id="background-1">Background</h5> <p>Code like the example above is sometimes written with the expectation that T&amp;&amp; will always end up being an rvalue reference, no matter what type is deduced for T, and that it is therefore not possible to pass an lvalue to foo(). However, this is not true. Consider this example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::string s = <span class="st">&quot;Hello, world&quot;</span>; foo(s);</code></pre></div> <p>This code compiles and, after the call to foo(), s is left in an indeterminate state because it has been moved from. This may be surprising to the caller of foo() because no std::move was used when calling foo().</p> <p>The reason for this behavior lies in the special rule for template argument deduction on function templates like foo() – i.e. on function templates that take an rvalue reference argument of a type that is a deduced function template argument. (See section [temp.deduct.call]/3 in the C++11 standard.)</p> <p>If foo() is called on an lvalue (as in the example above), then T is deduced to be an lvalue reference. In the example, T is deduced to be std::string &amp;. The type of the argument t therefore becomes std::string&amp; &amp;&amp;; by the reference collapsing rules, this collapses to std::string&amp;.</p> <p>This means that the foo(s) call passes s as an lvalue reference, and foo() ends up moving s and thereby placing it into an indeterminate state.</p> <p>(Clang-Tidy original name: bugprone-move-forwarding-reference)</p> + + + + Major + + + + + + + true + false + bugprone-misplaced-operator-in-strlen-in-alloc + bugprone + + true + Misplaced Operator In Strlen In Alloc + <p>Finds cases where 1 is added to the string in the argument to strlen(), strnlen(), strnlen_s(), wcslen(), wcsnlen(), and wcsnlen_s() instead of the result and the value is used as an argument to a memory allocation function (malloc(), calloc(), realloc(), alloca()) or the new[] operator in C++. The check detects error cases even if one of these functions (except the new[] operator) is called by a constant function pointer. Cases where 1 is added both to the parameter and the result of the strlen()-like function are ignored, as are cases where the whole addition is surrounded by extra parentheses.</p> <p>C example code:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> bad_malloc(<span class="dt">char</span> *str) { <span class="dt">char</span> *c = (<span class="dt">char</span>*) malloc(strlen(str + <span class="dv">1</span>)); }</code></pre></div> <p>The suggested fix is to add 1 to the return value of strlen() and not to its argument. In the example above the fix would be</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">char</span> *c = (<span class="dt">char</span>*) malloc(strlen(str) + <span class="dv">1</span>);</code></pre></div> <p>C++ example code:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> bad_new(<span class="dt">char</span> *str) { <span class="dt">char</span> *c = <span class="kw">new</span> <span class="dt">char</span>[strlen(str + <span class="dv">1</span>)]; }</code></pre></div> <p>As in the C code with the malloc() function, the suggested fix is to add 1 to the return value of strlen() and not to its argument. In the example above the fix would be</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">char</span> *c = <span class="kw">new</span> <span class="dt">char</span>[strlen(str) + <span class="dv">1</span>];</code></pre></div> <p>Example for silencing the diagnostic:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> bad_malloc(<span class="dt">char</span> *str) { <span class="dt">char</span> *c = (<span class="dt">char</span>*) malloc(strlen((str + <span class="dv">1</span>))); }</code></pre></div> <p>(Clang-Tidy original name: bugprone-misplaced-operator-in-strlen-in-alloc)</p> + + + + Major + + + + + + + true + false + bugprone-macro-parentheses + bugprone + + true + Macro Parentheses + <p>Finds macros that can have unexpected behaviour due to missing parentheses.</p> <p>Macros are expanded by the preprocessor as-is. As a result, there can be unexpected behaviour; operators may be evaluated in unexpected order and unary operators may become binary operators, etc.</p> <p>When the replacement list has an expression, it is recommended to surround it with parentheses. This ensures that the macro result is evaluated completely before it is used.</p> <p>It is also recommended to surround macro arguments in the replacement list with parentheses. This ensures that the argument value is calculated properly.</p> <p>(Clang-Tidy original name: bugprone-macro-parentheses)</p> <p>subl.. title:: clang-tidy - abseil-no-internal-dependencies</p> + + + + Major + + + + + + + true + false + bugprone-misplaced-pointer-arithmetic-in-alloc + bugprone + + true + Misplaced Pointer Arithmetic In Alloc + <p>Finds cases where an integer expression is added to or subtracted from the result of a memory allocation function (malloc(), calloc(), realloc(), alloca()) instead of its argument. The check detects error cases even if one of these functions is called by a constant function pointer.</p> <p>Example code:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> bad_malloc(<span class="dt">int</span> n) { <span class="dt">char</span> *p = (<span class="dt">char</span>*) malloc(n) + <span class="dv">10</span>; }</code></pre></div> <p>The suggested fix is to add the integer expression to the argument of malloc and not to its result. In the example above the fix would be</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">char</span> *p = (<span class="dt">char</span>*) malloc(n + <span class="dv">10</span>);</code></pre></div> <p>(Clang-Tidy original name: bugprone-misplaced-pointer-arithmetic-in-alloc)</p> + + + + Major + + + + + + + true + false + bugprone-macro-repeated-side-effects + bugprone + + true + Macro Repeated Side Effects + <p>Checks for repeated argument with side effects in macros.</p> <p>(Clang-Tidy original name: bugprone-macro-repeated-side-effects)</p> + + + + Major + + + + + + + true + false + bugprone-multiple-statement-macro + bugprone + + true + Multiple Statement Macro + <p>Detect multiple statement macros that are used in unbraced conditionals. Only the first statement of the macro will be inside the conditional and the other ones will be executed unconditionally.</p> <p>Example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#define INCREMENT_TWO(x, y) (x)++; (y)++</span> <span class="kw">if</span> (do_increment) INCREMENT_TWO(a, b); <span class="co">// (b)++ will be executed unconditionally.</span></code></pre></div> <p>(Clang-Tidy original name: bugprone-multiple-statement-macro)</p> + + + + Major + + + + + + + true + false + bugprone-misplaced-widening-cast + bugprone + + true + Misplaced Widening Cast + <p>This check will warn when there is a cast of a calculation result to a bigger type. If the intention of the cast is to avoid loss of precision then the cast is misplaced, and there can be loss of precision. Otherwise the cast is ineffective.</p> <p>Example code:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">long</span> f(<span class="dt">int</span> x) { <span class="kw">return</span> (<span class="dt">long</span>)(x * <span class="dv">1000</span>); }</code></pre></div> <p>The result x * 1000 is first calculated using int precision. If the result exceeds int precision there is loss of precision. Then the result is casted to long.</p> <p>If there is no loss of precision then the cast can be removed or you can explicitly cast to int instead.</p> <p>If you want to avoid loss of precision then put the cast in a proper location, for instance:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">long</span> f(<span class="dt">int</span> x) { <span class="kw">return</span> (<span class="dt">long</span>)x * <span class="dv">1000</span>; }</code></pre></div> <h5 id="implicit-casts">Implicit casts</h5> <p>Forgetting to place the cast at all is at least as dangerous and at least as common as misplacing it. If <a href="#cmdoption-arg-checkimplicitcasts">CheckImplicitCasts</a> is enabled the check also detects these cases, for instance:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">long</span> f(<span class="dt">int</span> x) { <span class="kw">return</span> x * <span class="dv">1000</span>; }</code></pre></div> <h5 id="floating-point">Floating point</h5> <p>Currently warnings are only written for integer conversion. No warning is written for this code:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">double</span> f(<span class="dt">float</span> x) { <span class="kw">return</span> (<span class="dt">double</span>)(x * <span class="fl">10.0f</span>); }</code></pre></div> <h5 id="options-18">Options</h5> <p>CheckImplicitCasts</p> <p>If true, enables detection of implicit casts. Default is true.</p> <p>(Clang-Tidy original name: bugprone-misplaced-widening-cast)</p> + + + + Major + + + + + + + true + false + bugprone-narrowing-conversions + bugprone + + true + Narrowing Conversions + + + + Major + + + + + + + true + false + bugprone-no-escape + bugprone + + true + No Escape + <p>Finds pointers with the noescape attribute that are captured by an asynchronously-executed block. The block arguments in dispatch_async() and dispatch_after() are guaranteed to escape, so it is an error if a pointer with the noescape attribute is captured by one of these blocks.</p> <p>The following is an example of an invalid use of the noescape attribute.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo(<span class="ot">__attribute__</span>((noescape)) <span class="dt">int</span> *p) { dispatch_async(queue, ^{ *p = <span class="dv">123</span>; }); });</code></pre></div> <p>(Clang-Tidy original name: bugprone-no-escape)</p> + + + + Major + + + + + + + true + false + bugprone-not-null-terminated-result + bugprone + + true + Not Null Terminated Result + <p>Finds function calls where it is possible to cause a not null-terminated result. Usually the proper length of a string is strlen(src) + 1 or equal length of this expression, because the null terminator needs an extra space. Without the null terminator it can result in undefined behaviour when the string is read.</p> <p>The following and their respective wchar_t based functions are checked:</p> <p>memcpy, memcpy_s, memchr, memmove, memmove_s, strerror_s, strncmp, strxfrm</p> <p>The following is a real-world example where the programmer forgot to increase the passed third argument, which is size_t length. That is why the length of the allocated memory is not enough to hold the null terminator.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">static</span> <span class="dt">char</span> *stringCpy(<span class="dt">const</span> std::string &amp;str) { <span class="dt">char</span> *result = <span class="kw">reinterpret_cast</span>&lt;<span class="dt">char</span> *&gt;(malloc(str.size())); memcpy(result, str.data(), str.size()); <span class="kw">return</span> result; }</code></pre></div> <p>In addition to issuing warnings, fix-it rewrites all the necessary code. It also tries to adjust the capacity of the destination array:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">static</span> <span class="dt">char</span> *stringCpy(<span class="dt">const</span> std::string &amp;str) { <span class="dt">char</span> *result = <span class="kw">reinterpret_cast</span>&lt;<span class="dt">char</span> *&gt;(malloc(str.size() + <span class="dv">1</span>)); strcpy(result, str.data()); <span class="kw">return</span> result; }</code></pre></div> <p>Note: It cannot guarantee to rewrite every of the path-sensitive memory allocations.</p> <h5 id="transformation-rules-of-memcpy">Transformation rules of ‘memcpy()’</h5> <p>It is possible to rewrite the memcpy() and memcpy_s() calls as the following four functions: strcpy(), strncpy(), strcpy_s(), strncpy_s(), where the latter two are the safer versions of the former two. It rewrites the wchar_t based memory handler functions respectively.</p> <h6 id="rewrite-based-on-the-destination-array">Rewrite based on the destination array</h6> <ul> <li>If copy to the destination array cannot overflow [1] the new function should be the older copy function (ending with cpy), because it is more efficient than the safe version.</li> <li>If copy to the destination array can overflow [1] and <a href="#cmdoption-arg-wanttousesafefunctions">WantToUseSafeFunctions</a> is set to true and it is possible to obtain the capacity of the destination array then the new function could be the safe version (ending with cpy_s).</li> <li>If the new function is could be safe version and C++ files are analysed and the destination array is plain char/wchar_t without un/signed then the length of the destination array can be omitted.</li> <li>If the new function is could be safe version and the destination array is un/signed it needs to be casted to plain char <em>/wchar_t </em>.</li> </ul> <p>[1] It is possible to overflow:</p> <ul> <li>If the capacity of the destination array is unknown.</li> <li>If the given length is equal to the destination array’s capacity.</li> </ul> <h6 id="rewrite-based-on-the-length-of-the-source-string">Rewrite based on the length of the source string</h6> <ul> <li>If the given length is strlen(source) or equal length of this expression then the new function should be the older copy function (ending with cpy), as it is more efficient than the safe version (ending with cpy_s).</li> <li>Otherwise we assume that the programmer wanted to copy ‘N’ characters, so the new function is ncpy-like which copies ‘N’ characters.</li> </ul> <h5 id="transformations-with-strlen-or-equal-length-of-this-expression">Transformations with ‘strlen()’ or equal length of this expression</h5> <p>It transforms the wchar_t based memory and string handler functions respectively (where only strerror_s does not have wchar_t based alias).</p> <h6 id="memory-handler-functions">Memory handler functions</h6> <p>memcpy Please visit the <a href="#memcpytransformation">Transformation rules of ‘memcpy()’</a> section.</p> <p>memchr Usually there is a C-style cast and it is needed to be removed, because the new function strchr’s return type is correct. The given length is going to be removed.</p> <p>memmove If safe functions are available the new function is memmove_s, which has a new second argument which is the length of the destination array, it is adjusted, and the length of the source string is incremented by one. If safe functions are not available the given length is incremented by one.</p> <p>memmove_s The given length is incremented by one.</p> <h6 id="string-handler-functions">String handler functions</h6> <p>strerror_s The given length is incremented by one.</p> <p>strncmp If the third argument is the first or the second argument’s length + 1 it has to be truncated without the + 1 operation.</p> <p>strxfrm The given length is incremented by one.</p> <h5 id="options-51">Options</h5> <p>WantToUseSafeFunctions</p> <p>The value true specifies that the target environment is considered to implement ‘_s’ suffixed memory and string handler functions which are safer than older versions (e.g. ‘memcpy_s()’). The default value is true.</p> <p>(Clang-Tidy original name: bugprone-not-null-terminated-result)</p> + + + + Major + + + + + + + true + false + bugprone-posix-return + bugprone + + true + Posix Return + <p>Checks if any calls to pthread_* or posix_* functions (except posix_openpt) expect negative return values. These functions return either 0 on success or an errno on failure, which is positive only.</p> <p>Example buggy usage looks like:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">if</span> (posix_fadvise(...) &lt; <span class="dv">0</span>) {</code></pre></div> <p>This will never happen as the return value is always non-negative. A simple fix could be:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">if</span> (posix_fadvise(...) &gt; <span class="dv">0</span>) {</code></pre></div> <p>(Clang-Tidy original name: bugprone-posix-return)</p> + + + + Major + + + + + + + true + false + bugprone-parent-virtual-call + bugprone + + true + Parent Virtual Call + <p>Detects and fixes calls to grand-…parent virtual methods instead of calls to overridden parent’s virtual methods.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> A { <span class="dt">int</span> <span class="kw">virtual</span> foo() {...} }; <span class="kw">struct</span> B: <span class="kw">public</span> A { <span class="dt">int</span> foo() <span class="kw">override</span> {...} }; <span class="kw">struct</span> C: <span class="kw">public</span> B { <span class="dt">int</span> foo() <span class="kw">override</span> { A::foo(); } <span class="co">// ^^^^^^^^</span> <span class="co">// warning: qualified name A::foo refers to a member overridden in subclass; did you mean &#39;B&#39;? [bugprone-parent-virtual-call]</span> };</code></pre></div> <p>(Clang-Tidy original name: bugprone-parent-virtual-call)</p> + + + + Major + + + + + + + true + false + bugprone-redundant-branch-condition + bugprone + + true + Redundant Branch Condition + <p>Finds condition variables in nested if statements that were also checked in the outer if statement and were not changed.</p> <p>Simple example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">bool</span> onFire = isBurning(); <span class="kw">if</span> (onFire) { <span class="kw">if</span> (onFire) scream(); }</code></pre></div> <p>Here onFire is checked both in the outer if and the inner if statement without a possible change between the two checks. The check warns for this code and suggests removal of the second checking of variable onFire.</p> <p>The checker also detects redundant condition checks if the condition variable is an operand of a logical “and” (&amp;&amp;) or a logical “or” (||) operator:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">bool</span> onFire = isBurning(); <span class="kw">if</span> (onFire) { <span class="kw">if</span> (onFire &amp;&amp; peopleInTheBuilding &gt; <span class="dv">0</span>) scream(); }</code></pre></div> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">bool</span> onFire = isBurning(); <span class="kw">if</span> (onFire) { <span class="kw">if</span> (onFire || isCollapsing()) scream(); }</code></pre></div> <p>In the first case (logical “and”) the suggested fix is to remove the redundant condition variable and keep the other side of the &amp;&amp;. In the second case (logical “or”) the whole if is removed similarily to the simple case on the top.</p> <p>The condition of the outer if statement may also be a logical “and” (&amp;&amp;) expression:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">bool</span> onFire = isBurning(); <span class="kw">if</span> (onFire &amp;&amp; fireFighters &lt; <span class="dv">10</span>) { <span class="kw">if</span> (someOtherCondition()) { <span class="kw">if</span> (onFire) scream(); } }</code></pre></div> <p>The error is also detected if both the outer statement is a logical “and” (&amp;&amp;) and the inner statement is a logical “and” (&amp;&amp;) or “or” (||). The inner if statement does not have to be a direct descendant of the outer one.</p> <p>No error is detected if the condition variable may have been changed between the two checks:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">bool</span> onFire = isBurning(); <span class="kw">if</span> (onFire) { tryToExtinguish(onFire); <span class="kw">if</span> (onFire &amp;&amp; peopleInTheBuilding &gt; <span class="dv">0</span>) scream(); }</code></pre></div> <p>Every possible change is considered, thus if the condition variable is not a local variable of the function, it is a volatile or it has an alias (pointer or reference) then no warning is issued.</p> <h5 id="known-limitations-3">Known limitations</h5> <p>The else branch is not checked currently for negated condition variable:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">bool</span> onFire = isBurning(); <span class="kw">if</span> (onFire) { scream(); } <span class="kw">else</span> { <span class="kw">if</span> (!onFire) { continueWork(); } }</code></pre></div> <p>The checker currently only detects redundant checking of single condition variables. More complex expressions are not checked:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">if</span> (peopleInTheBuilding == <span class="dv">1</span>) { <span class="kw">if</span> (peopleInTheBuilding == <span class="dv">1</span>) { doSomething(); } }</code></pre></div> <p>(Clang-Tidy original name: bugprone-redundant-branch-condition)</p> + + + + Major + + + + + + + true + false + bugprone-reserved-identifier + bugprone + + true + Reserved Identifier + <p>cert-dcl37-c and cert-dcl51-cpp redirect here as an alias for this check.</p> <p>Checks for usages of identifiers reserved for use by the implementation.</p> <p>The C and C++ standards both reserve the following names for such use:</p> <ul> <li>identifiers that begin with an underscore followed by an uppercase letter;</li> <li>identifiers in the global namespace that begin with an underscore.</li> </ul> <p>The C standard additionally reserves names beginning with a double underscore, while the C++ standard strengthens this to reserve names with a double underscore occurring anywhere.</p> <p>Violating the naming rules above results in undefined behavior.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">namespace</span> NS { <span class="dt">void</span> __f(); <span class="co">// name is not allowed in user code</span> <span class="kw">using</span> _Int = <span class="dt">int</span>; <span class="co">// same with this</span> <span class="ot">#define cool__macro </span><span class="co">// also this</span> } <span class="dt">int</span> _g(); <span class="co">// disallowed in global namespace only</span></code></pre></div> <p>The check can also be inverted, i.e. it can be configured to flag any identifier that is <em>not</em> a reserved identifier. This mode is for use by e.g. standard library implementors, to ensure they don’t infringe on the user namespace.</p> <p>This check does not (yet) check for other reserved names, e.g. macro names identical to language keywords, and names specifically reserved by language standards, e.g. C++ ‘zombie names’ and C future library directions.</p> <p>This check corresponds to CERT C Coding Standard rule <a href="https://wiki.sei.cmu.edu/confluence/display/c/DCL37-C.+Do+not+declare+or+define+a+reserved+identifier">DCL37-C. Do not declare or define a reserved identifier</a> as well as its C++ counterpart, <a href="https://wiki.sei.cmu.edu/confluence/display/cplusplus/DCL51-CPP.+Do+not+declare+or+define+a+reserved+identifier">DCL51-CPP. Do not declare or define a reserved identifier</a>.</p> <h5 id="options-34">Options</h5> <p>Invert</p> <p>If true, inverts the check, i.e. flags names that are not reserved. Default is false.</p> <p>AllowedIdentifiers</p> <p>Semicolon-separated list of names that the check ignores. Default is an empty list.</p> <p>(Clang-Tidy original name: bugprone-reserved-identifier)</p> + + + + Major + + + + + + + true + false + bugprone-swapped-arguments + bugprone + + true + Swapped Arguments + <p>Finds potentially swapped arguments by looking at implicit conversions.</p> <p>(Clang-Tidy original name: bugprone-swapped-arguments)</p> + + + + Major + + + + + + + true + false + bugprone-sizeof-container + bugprone + + true + Sizeof Container + <p>The check finds usages of sizeof on expressions of STL container types. Most likely the user wanted to use .size() instead.</p> <p>All class/struct types declared in namespace std:: having a const size() method are considered containers, with the exception of std::bitset and std::array.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::string s; <span class="dt">int</span> a = <span class="dv">47</span> + <span class="kw">sizeof</span>(s); <span class="co">// warning: sizeof() doesn&#39;t return the size of the container. Did you mean .size()?</span> <span class="dt">int</span> b = <span class="kw">sizeof</span>(std::string); <span class="co">// no warning, probably intended.</span> std::string array_of_strings[<span class="dv">10</span>]; <span class="dt">int</span> c = <span class="kw">sizeof</span>(array_of_strings) / <span class="kw">sizeof</span>(array_of_strings[<span class="dv">0</span>]); <span class="co">// no warning, definitely intended.</span> std::array&lt;<span class="dt">int</span>, <span class="dv">3</span>&gt; std_array; <span class="dt">int</span> d = <span class="kw">sizeof</span>(std_array); <span class="co">// no warning, probably intended.</span></code></pre></div> <p>(Clang-Tidy original name: bugprone-sizeof-container)</p> + + + + Major + + + + + + + true + false + bugprone-string-constructor + bugprone + + true + String Constructor + <p>Finds string constructors that are suspicious and probably errors.</p> <p>A common mistake is to swap parameters to the ‘fill’ string-constructor.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::string str(<span class="st">&#39;x&#39;</span>, <span class="dv">50</span>); <span class="co">// should be str(50, &#39;x&#39;)</span></code></pre></div> <p>Calling the string-literal constructor with a length bigger than the literal is suspicious and adds extra random characters to the string.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::string(<span class="st">&quot;test&quot;</span>, <span class="dv">200</span>); <span class="co">// Will include random characters after &quot;test&quot;.</span> std::string_view(<span class="st">&quot;test&quot;</span>, <span class="dv">200</span>);</code></pre></div> <p>Creating an empty string from constructors with parameters is considered suspicious. The programmer should use the empty constructor instead.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::string(<span class="st">&quot;test&quot;</span>, <span class="dv">0</span>); <span class="co">// Creation of an empty string.</span> std::string_view(<span class="st">&quot;test&quot;</span>, <span class="dv">0</span>);</code></pre></div> <h5 id="options-77">Options</h5> <p>WarnOnLargeLength</p> <p>When true, the check will warn on a string with a length greater than <a href="#cmdoption-arg-largelengththreshold">LargeLengthThreshold</a>. Default is true.</p> <p>LargeLengthThreshold</p> <p>An integer specifying the large length threshold. Default is 0x800000.</p> <p>StringNames</p> <p>Default is ::std::basic_string;::std::basic_string_view.</p> <p>Semicolon-delimited list of class names to apply this check to. By default ::std::basic_string applies to std::string and std::wstring. Set to e.g. ::std::basic_string;llvm::StringRef;QString to perform this check on custom classes.</p> <p>(Clang-Tidy original name: bugprone-string-constructor)</p> + + + + Major + + + + + + + true + false + bugprone-signed-char-misuse + bugprone + + true + Signed Char Misuse + <p>cert-str34-c redirects here as an alias for this check. For the CERT alias, the DiagnoseSignedUnsignedCharComparisons option is set to false.</p> <p>Finds those signed char -&gt; integer conversions which might indicate a programming error. The basic problem with the signed char, that it might store the non-ASCII characters as negative values. This behavior can cause a misunderstanding of the written code both when an explicit and when an implicit conversion happens.</p> <p>When the code contains an explicit signed char -&gt; integer conversion, the human programmer probably expects that the converted value matches with the character code (a value from [0..255]), however, the actual value is in [-128..127] interval. To avoid this kind of misinterpretation, the desired way of converting from a signed char to an integer value is converting to unsigned char first, which stores all the characters in the positive [0..255] interval which matches the known character codes.</p> <p>In case of implicit conversion, the programmer might not actually be aware that a conversion happened and char value is used as an integer. There are some use cases when this unawareness might lead to a functionally imperfect code. For example, checking the equality of a signed char and an unsigned char variable is something we should avoid in C++ code. During this comparison, the two variables are converted to integers which have different value ranges. For signed char, the non-ASCII characters are stored as a value in [-128..-1] interval, while the same characters are stored in the [128..255] interval for an unsigned char.</p> <p>It depends on the actual platform whether plain char is handled as signed char by default and so it is caught by this check or not. To change the default behavior you can use -funsigned-char and -fsigned-char compilation options.</p> <p>Currently, this check warns in the following cases: - signed char is assigned to an integer variable - signed char and unsigned char are compared with equality/inequality operator - signed char is converted to an integer in the array subscript</p> <p>See also: <a href="https://wiki.sei.cmu.edu/confluence/display/c/STR34-C.+Cast+characters+to+unsigned+char+before+converting+to+larger+integer+sizes">STR34-C. Cast characters to unsigned char before converting to larger integer sizes</a></p> <p>A good example from the CERT description when a char variable is used to read from a file that might contain non-ASCII characters. The problem comes up when the code uses the -1 integer value as EOF, while the 255 character code is also stored as -1 in two’s complement form of char type. See a simple example of this bellow. This code stops not only when it reaches the end of the file, but also when it gets a character with the 255 code.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#define EOF (-1)</span> <span class="dt">int</span> read(<span class="dt">void</span>) { <span class="dt">char</span> CChar; <span class="dt">int</span> IChar = EOF; <span class="kw">if</span> (readChar(CChar)) { IChar = CChar; } <span class="kw">return</span> IChar; }</code></pre></div> <p>A proper way to fix the code above is converting the char variable to an unsigned char value first.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#define EOF (-1)</span> <span class="dt">int</span> read(<span class="dt">void</span>) { <span class="dt">char</span> CChar; <span class="dt">int</span> IChar = EOF; <span class="kw">if</span> (readChar(CChar)) { IChar = <span class="kw">static_cast</span>&lt;<span class="dt">unsigned</span> <span class="dt">char</span>&gt;(CChar); } <span class="kw">return</span> IChar; }</code></pre></div> <p>Another use case is checking the equality of two char variables with different signedness. Inside the non-ASCII value range this comparison between a signed char and an unsigned char always returns false.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">bool</span> compare(<span class="dt">signed</span> <span class="dt">char</span> SChar, <span class="dt">unsigned</span> <span class="dt">char</span> USChar) { <span class="kw">if</span> (SChar == USChar) <span class="kw">return</span> <span class="kw">true</span>; <span class="kw">return</span> <span class="kw">false</span>; }</code></pre></div> <p>The easiest way to fix this kind of comparison is casting one of the arguments, so both arguments will have the same type.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">bool</span> compare(<span class="dt">signed</span> <span class="dt">char</span> SChar, <span class="dt">unsigned</span> <span class="dt">char</span> USChar) { <span class="kw">if</span> (<span class="kw">static_cast</span>&lt;<span class="dt">unsigned</span> <span class="dt">char</span>&gt;(SChar) == USChar) <span class="kw">return</span> <span class="kw">true</span>; <span class="kw">return</span> <span class="kw">false</span>; }</code></pre></div> <p>CharTypdefsToIgnore</p> <p>A semicolon-separated list of typedef names. In this list, we can list typedefs for char or signed char, which will be ignored by the check. This is useful when a typedef introduces an integer alias like sal_Int8 or int8_t. In this case, human misinterpretation is not an issue.</p> <p>DiagnoseSignedUnsignedCharComparisons</p> <p>When true, the check will warn on signed char/unsigned char comparisons, otherwise these comparisons are ignored. By default, this option is set to true.</p> <p>(Clang-Tidy original name: bugprone-signed-char-misuse)</p> + + + + Major + + + + + + + true + false + bugprone-sizeof-expression + bugprone + + true + Sizeof Expression + <p>The check finds usages of sizeof expressions which are most likely errors.</p> <p>The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. Misuse of this operator may be leading to errors and possible software vulnerabilities.</p> <h5 id="suspicious-usage-of-sizeofk">Suspicious usage of ‘sizeof(K)’</h5> <p>A common mistake is to query the sizeof of an integer literal. This is equivalent to query the size of its type (probably int). The intent of the programmer was probably to simply get the integer and not its size.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#define BUFLEN 42</span> <span class="dt">char</span> buf[BUFLEN]; memset(buf, <span class="dv">0</span>, <span class="kw">sizeof</span>(BUFLEN)); <span class="co">// sizeof(42) ==&gt; sizeof(int)</span></code></pre></div> <h5 id="suspicious-usage-of-sizeofexpr">Suspicious usage of ‘sizeof(expr)’</h5> <p>In cases, where there is an enum or integer to represent a type, a common mistake is to query the sizeof on the integer or enum that represents the type that should be used by sizeof. This results in the size of the integer and not of the type the integer represents:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">enum</span> data_type { FLOAT_TYPE, DOUBLE_TYPE }; <span class="kw">struct</span> data { data_type type; <span class="dt">void</span>* buffer; data_type get_type() { <span class="kw">return</span> type; } }; <span class="dt">void</span> f(data d, <span class="dt">int</span> numElements) { <span class="co">// should be sizeof(float) or sizeof(double), depending on d.get_type()</span> <span class="dt">int</span> numBytes = numElements * <span class="kw">sizeof</span>(d.get_type()); ... }</code></pre></div> <h5 id="suspicious-usage-of-sizeofthis">Suspicious usage of ‘sizeof(this)’</h5> <p>The this keyword is evaluated to a pointer to an object of a given type. The expression sizeof(this) is returning the size of a pointer. The programmer most likely wanted the size of the object and not the size of the pointer.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Point { [...] size_t size() { <span class="kw">return</span> <span class="kw">sizeof</span>(<span class="kw">this</span>); } <span class="co">// should probably be sizeof(*this)</span> [...] };</code></pre></div> <h5 id="suspicious-usage-of-sizeofchar">Suspicious usage of ‘sizeof(char*)’</h5> <p>There is a subtle difference between declaring a string literal with char* A = &quot;&quot; and char A[] = &quot;&quot;. The first case has the type char* instead of the aggregate type char[]. Using sizeof on an object declared with char* type is returning the size of a pointer instead of the number of characters (bytes) in the string literal.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">const</span> <span class="dt">char</span>* kMessage = <span class="st">&quot;Hello World!&quot;</span>; <span class="co">// const char kMessage[] = &quot;...&quot;;</span> <span class="dt">void</span> getMessage(<span class="dt">char</span>* buf) { memcpy(buf, kMessage, <span class="kw">sizeof</span>(kMessage)); <span class="co">// sizeof(char*)</span> }</code></pre></div> <h5 id="suspicious-usage-of-sizeofa">Suspicious usage of ‘sizeof(A*)’</h5> <p>A common mistake is to compute the size of a pointer instead of its pointee. These cases may occur because of explicit cast or implicit conversion.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> A[<span class="dv">10</span>]; memset(A, <span class="dv">0</span>, <span class="kw">sizeof</span>(A + <span class="dv">0</span>)); <span class="kw">struct</span> Point point; memset(point, <span class="dv">0</span>, <span class="kw">sizeof</span>(&amp;point));</code></pre></div> <h5 id="suspicious-usage-of-sizeofsizeof">Suspicious usage of ‘sizeof(…)/sizeof(…)’</h5> <p>Dividing sizeof expressions is typically used to retrieve the number of elements of an aggregate. This check warns on incompatible or suspicious cases.</p> <p>In the following example, the entity has 10-bytes and is incompatible with the type int which has 4 bytes.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">char</span> buf[] = { <span class="dv">0</span>, <span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">4</span>, <span class="dv">5</span>, <span class="dv">6</span>, <span class="dv">7</span>, <span class="dv">8</span>, <span class="dv">9</span> }; <span class="co">// sizeof(buf) =&gt; 10</span> <span class="dt">void</span> getMessage(<span class="dt">char</span>* dst) { memcpy(dst, buf, <span class="kw">sizeof</span>(buf) / <span class="kw">sizeof</span>(<span class="dt">int</span>)); <span class="co">// sizeof(int) =&gt; 4 [incompatible sizes]</span> }</code></pre></div> <p>In the following example, the expression sizeof(Values) is returning the size of char<em>. One can easily be fooled by its declaration, but in parameter declaration the size ‘10’ is ignored and the function is receiving a char</em>.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">char</span> OrderedValues[<span class="dv">10</span>] = { <span class="dv">0</span>, <span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">4</span>, <span class="dv">5</span>, <span class="dv">6</span>, <span class="dv">7</span>, <span class="dv">8</span>, <span class="dv">9</span> }; <span class="kw">return</span> CompareArray(<span class="dt">char</span> Values[<span class="dv">10</span>]) { <span class="kw">return</span> memcmp(OrderedValues, Values, <span class="kw">sizeof</span>(Values)) == <span class="dv">0</span>; <span class="co">// sizeof(Values) ==&gt; sizeof(char*) [implicit cast to char*]</span> }</code></pre></div> <h5 id="suspicious-sizeof-by-sizeof-expression">Suspicious ‘sizeof’ by ‘sizeof’ expression</h5> <p>Multiplying sizeof expressions typically makes no sense and is probably a logic error. In the following example, the programmer used * instead of /.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">const</span> <span class="dt">char</span> kMessage[] = <span class="st">&quot;Hello World!&quot;</span>; <span class="dt">void</span> getMessage(<span class="dt">char</span>* buf) { memcpy(buf, kMessage, <span class="kw">sizeof</span>(kMessage) * <span class="kw">sizeof</span>(<span class="dt">char</span>)); <span class="co">// sizeof(kMessage) / sizeof(char)</span> }</code></pre></div> <p>This check may trigger on code using the arraysize macro. The following code is working correctly but should be simplified by using only the sizeof operator.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">extern</span> Object objects[<span class="dv">100</span>]; <span class="dt">void</span> InitializeObjects() { memset(objects, <span class="dv">0</span>, arraysize(objects) * <span class="kw">sizeof</span>(Object)); <span class="co">// sizeof(objects)</span> }</code></pre></div> <h5 id="suspicious-usage-of-sizeofsizeof-1">Suspicious usage of ‘sizeof(sizeof(…))’</h5> <p>Getting the sizeof of a sizeof makes no sense and is typically an error hidden through macros.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#define INT_SZ sizeof(int)</span> <span class="dt">int</span> buf[] = { <span class="dv">42</span> }; <span class="dt">void</span> getInt(<span class="dt">int</span>* dst) { memcpy(dst, buf, <span class="kw">sizeof</span>(INT_SZ)); <span class="co">// sizeof(sizeof(int)) is suspicious.</span> }</code></pre></div> <h5 id="options-30">Options</h5> <p>WarnOnSizeOfConstant</p> <p>When true, the check will warn on an expression like sizeof(CONSTANT). Default is true.</p> <p>WarnOnSizeOfIntegerExpression</p> <p>When true, the check will warn on an expression like sizeof(expr) where the expression results in an integer. Default is false.</p> <p>WarnOnSizeOfThis</p> <p>When true, the check will warn on an expression like sizeof(this). Default is true.</p> <p>WarnOnSizeOfCompareToConstant</p> <p>When true, the check will warn on an expression like sizeof(epxr) &lt;= k for a suspicious constant k while k is 0 or greater than 0x8000. Default is true.</p> <p>(Clang-Tidy original name: bugprone-sizeof-expression)</p> + + + + Major + + + + + + + true + false + bugprone-suspicious-enum-usage + bugprone + + true + Suspicious Enum Usage + <p>The checker detects various cases when an enum is probably misused (as a bitmask ).</p> <ol style="list-style-type: decimal"> <li>When “ADD” or “bitwise OR” is used between two enum which come from different types and these types value ranges are not disjoint.</li> </ol> <p>The following cases will be investigated only using <a href="performance-inefficient-string-concatenation.html#cmdoption-arg-strictmode">StrictMode</a>. We regard the enum as a (suspicious) bitmask if the three conditions below are true at the same time:</p> <ul> <li>at most half of the elements of the enum are non pow-of-2 numbers (because of short enumerations)</li> <li>there is another non pow-of-2 number than the enum constant representing all choices (the result “bitwise OR” operation of all enum elements)</li> <li>enum type variable/enumconstant is used as an argument of a + or “bitwise OR ” operator</li> </ul> <p>So whenever the non pow-of-2 element is used as a bitmask element we diagnose a misuse and give a warning.</p> <ol start="2" style="list-style-type: decimal"> <li>Investigating the right hand side of += and |= operator.</li> <li>Check only the enum value side of a | and + operator if one of them is not enum val.</li> <li>Check both side of | or + operator where the enum values are from the same enum type.</li> </ol> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">enum</span> { A, B, C }; <span class="kw">enum</span> { D, E, F = <span class="dv">5</span> }; <span class="kw">enum</span> { G = <span class="dv">10</span>, H = <span class="dv">11</span>, I = <span class="dv">12</span> }; <span class="dt">unsigned</span> flag; flag = A | H; <span class="co">// OK, disjoint value intervals in the enum types -&gt;probably good use.</span> flag = B | F; <span class="co">// Warning, have common values so they are probably misused.</span> <span class="co">// Case 2:</span> <span class="kw">enum</span> Bitmask { A = <span class="dv">0</span>, B = <span class="dv">1</span>, C = <span class="dv">2</span>, D = <span class="dv">4</span>, E = <span class="dv">8</span>, F = <span class="dv">16</span>, G = <span class="dv">31</span> <span class="co">// OK, real bitmask.</span> }; <span class="kw">enum</span> Almostbitmask { AA = <span class="dv">0</span>, BB = <span class="dv">1</span>, CC = <span class="dv">2</span>, DD = <span class="dv">4</span>, EE = <span class="dv">8</span>, FF = <span class="dv">16</span>, GG <span class="co">// Problem, forgot to initialize.</span> }; <span class="dt">unsigned</span> flag = <span class="dv">0</span>; flag |= E; <span class="co">// OK.</span> flag |= EE; <span class="co">// Warning at the decl, and note that it was used here as a bitmask.</span></code></pre></div> <h5 id="options-43">Options</h5> <p>StrictMode</p> <p>Default value: 0. When non-null the suspicious bitmask usage will be investigated additionally to the different enum usage check.</p> <p>(Clang-Tidy original name: bugprone-suspicious-enum-usage)</p> + + + + Major + + + + + + + true + false + bugprone-signal-handler + bugprone + + true + Signal Handler + <p>Finds functions registered as signal handlers that call non asynchronous-safe functions. Any function that cannot be determined to be an asynchronous-safe function call is assumed to be non-asynchronous-safe by the checker, including user functions for which only the declaration is visible. User function calls with visible definition are checked recursively. The check handles only C code.</p> <p>The minimal list of asynchronous-safe system functions is: abort(), _Exit(), quick_exit() and signal() (for signal there are additional conditions that are not checked). The check accepts only these calls as asynchronous-safe.</p> <p>This check corresponds to the CERT C Coding Standard rule <a href="https://www.securecoding.cert.org/confluence/display/c/SIG30-C.+Call+only+asynchronous-safe+functions+within+signal+handlers">SIG30-C. Call only asynchronous-safe functions within signal handlers</a>.</p> <p>(Clang-Tidy original name: bugprone-signal-handler)</p> + + + + Major + + + + + + + true + false + bugprone-suspicious-include + bugprone + + true + Suspicious Include + <p>The check detects various cases when an include refers to what appears to be an implementation file, which often leads to hard-to-track-down ODR violations.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#include &quot;Dinosaur.hpp&quot; </span><span class="co">// OK, .hpp files tend not to have definitions.</span> <span class="ot">#include &quot;Pterodactyl.h&quot; </span><span class="co">// OK, .h files tend not to have definitions.</span> <span class="ot">#include &quot;Velociraptor.cpp&quot; </span><span class="co">// Warning, filename is suspicious.</span> <span class="ot">#include_next &lt;stdio.c&gt; </span><span class="co">// Warning, filename is suspicious.</span></code></pre></div> <h5 id="options-68">Options</h5> <p>HeaderFileExtensions</p> <p>Default value: &quot;;h;hh;hpp;hxx&quot; A semicolon-separated list of filename extensions of header files (the filename extensions should not contain a “.” prefix). For extension-less header files, use an empty string or leave an empty string between “;” if there are other filename extensions.</p> <p>ImplementationFileExtensions</p> <p>Default value: &quot;c;cc;cpp;cxx&quot; Likewise, a semicolon-separated list of filename extensions of implementation files.</p> <p>(Clang-Tidy original name: bugprone-suspicious-include)</p> + + + + Major + + + + + + + true + false + bugprone-string-integer-assignment + bugprone + + true + String Integer Assignment + <p>The check finds assignments of an integer to std::basic_string<CharT> (std::string, std::wstring, etc.). The source of the problem is the following assignment operator of std::basic_string<CharT>:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">basic_string&amp; <span class="kw">operator</span>=( CharT ch );</code></pre></div> <p>Numeric types can be implicitly casted to character types.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::string s; <span class="dt">int</span> x = <span class="dv">5965</span>; s = <span class="dv">6</span>; s = x;</code></pre></div> <p>Use the appropriate conversion functions or character literals.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::string s; <span class="dt">int</span> x = <span class="dv">5965</span>; s = <span class="st">&#39;6&#39;</span>; s = std::to_string(x);</code></pre></div> <p>In order to suppress false positives, use an explicit cast.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::string s; s = <span class="kw">static_cast</span>&lt;<span class="dt">char</span>&gt;(<span class="dv">6</span>);</code></pre></div> <p>(Clang-Tidy original name: bugprone-string-integer-assignment)</p> + + + + Major + + + + + + + true + false + bugprone-string-literal-with-embedded-nul + bugprone + + true + String Literal With Embedded Nul + <p>Finds occurrences of string literal with embedded NUL character and validates their usage.</p> <h5 id="invalid-escaping">Invalid escaping</h5> <p>Special characters can be escaped within a string literal by using their hexadecimal encoding like 42. A common mistake is to escape them like this x42 where the stands for the NUL character.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">const</span> <span class="dt">char</span>* Example[] = <span class="st">&quot;Invalid character: \0x12 should be </span><span class="ch">\x12</span><span class="st">&quot;</span>; <span class="dt">const</span> <span class="dt">char</span>* Bytes[] = <span class="st">&quot;</span><span class="ch">\x03</span><span class="st">\0x02\0x01\0x00\0xFF\0xFF\0xFF&quot;</span>;</code></pre></div> <h5 id="truncated-literal">Truncated literal</h5> <p>String-like classes can manipulate strings with embedded NUL as they are keeping track of the bytes and the length. This is not the case for a char* (NUL-terminated) string.</p> <p>A common mistake is to pass a string-literal with embedded NUL to a string constructor expecting a NUL-terminated string. The bytes after the first NUL character are truncated.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::string str(<span class="st">&quot;abc\0def&quot;</span>); <span class="co">// &quot;def&quot; is truncated</span> str += <span class="st">&quot;\0&quot;</span>; <span class="co">// This statement is doing nothing</span> <span class="kw">if</span> (str == <span class="st">&quot;\0abc&quot;</span>) <span class="kw">return</span>; <span class="co">// This expression is always true</span></code></pre></div> <p>(Clang-Tidy original name: bugprone-string-literal-with-embedded-nul)</p> + + + + Major + + + + + + + true + false + bugprone-suspicious-missing-comma + bugprone + + true + Suspicious Missing Comma + <p>String literals placed side-by-side are concatenated at translation phase 6 (after the preprocessor). This feature is used to represent long string literal on multiple lines.</p> <p>For instance, the following declarations are equivalent:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">const</span> <span class="dt">char</span>* A[] = <span class="st">&quot;This is a test&quot;</span>; <span class="dt">const</span> <span class="dt">char</span>* B[] = <span class="st">&quot;This&quot;</span> <span class="st">&quot; is a &quot;</span> <span class="st">&quot;test&quot;</span>;</code></pre></div> <p>A common mistake done by programmers is to forget a comma between two string literals in an array initializer list.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">const</span> <span class="dt">char</span>* Test[] = { <span class="st">&quot;line 1&quot;</span>, <span class="st">&quot;line 2&quot;</span> <span class="co">// Missing comma!</span> <span class="st">&quot;line 3&quot;</span>, <span class="st">&quot;line 4&quot;</span>, <span class="st">&quot;line 5&quot;</span> };</code></pre></div> <p>The array contains the string “line 2line3” at offset 1 (i.e. Test[1]). Clang won’t generate warnings at compile time.</p> <p>This check may warn incorrectly on cases like:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">const</span> <span class="dt">char</span>* SupportedFormat[] = { <span class="st">&quot;Error </span><span class="ch">%s</span><span class="st">&quot;</span>, <span class="st">&quot;Code &quot;</span> PRIu64, <span class="co">// May warn here.</span> <span class="st">&quot;Warning </span><span class="ch">%s</span><span class="st">&quot;</span>, };</code></pre></div> <h5 id="options-32">Options</h5> <p>SizeThreshold</p> <p>An unsigned integer specifying the minimum size of a string literal to be considered by the check. Default is 5U.</p> <p>RatioThreshold</p> <p>A string specifying the maximum threshold ratio [0, 1.0] of suspicious string literals to be considered. Default is &quot;.2&quot;.</p> <p>MaxConcatenatedTokens</p> <p>An unsigned integer specifying the maximum number of concatenated tokens. Default is 5U.</p> <p>(Clang-Tidy original name: bugprone-suspicious-missing-comma)</p> + + + + Major + + + + + + + true + false + bugprone-suspicious-memset-usage + bugprone + + true + Suspicious Memset Usage + <p>This check finds memset() calls with potential mistakes in their arguments. Considering the function as void* memset(void* destination, int fill_value, size_t byte_count), the following cases are covered:</p> <p><strong>Case 1: Fill value is a character <code>’0’</code></strong></p> <p>Filling up a memory area with ASCII code 48 characters is not customary, possibly integer zeroes were intended instead. The check offers a replacement of '0' with 0. Memsetting character pointers with '0' is allowed.</p> <p><strong>Case 2: Fill value is truncated</strong></p> <p>Memset converts fill_value to unsigned char before using it. If fill_value is out of unsigned character range, it gets truncated and memory will not contain the desired pattern.</p> <p><strong>Case 3: Byte count is zero</strong></p> <p>Calling memset with a literal zero in its byte_count argument is likely to be unintended and swapped with fill_value. The check offers to swap these two arguments.</p> <p>Corresponding cpplint.py check name: runtime/memset.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo() { <span class="dt">int</span> i[<span class="dv">5</span>] = {<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">4</span>, <span class="dv">5</span>}; <span class="dt">int</span> *ip = i; <span class="dt">char</span> c = <span class="st">&#39;1&#39;</span>; <span class="dt">char</span> *cp = &amp;c; <span class="dt">int</span> v = <span class="dv">0</span>; <span class="co">// Case 1</span> memset(ip, <span class="st">&#39;0&#39;</span>, <span class="dv">1</span>); <span class="co">// suspicious</span> memset(cp, <span class="st">&#39;0&#39;</span>, <span class="dv">1</span>); <span class="co">// OK</span> <span class="co">// Case 2</span> memset(ip, <span class="bn">0xabcd</span>, <span class="dv">1</span>); <span class="co">// fill value gets truncated</span> memset(ip, <span class="bn">0x00</span>, <span class="dv">1</span>); <span class="co">// OK</span> <span class="co">// Case 3</span> memset(ip, <span class="kw">sizeof</span>(<span class="dt">int</span>), v); <span class="co">// zero length, potentially swapped</span> memset(ip, <span class="dv">0</span>, <span class="dv">1</span>); <span class="co">// OK</span> }</code></pre></div> <p>(Clang-Tidy original name: bugprone-suspicious-memset-usage)</p> + + + + Major + + + + + + + true + false + bugprone-suspicious-semicolon + bugprone + + true + Suspicious Semicolon + <p>Finds most instances of stray semicolons that unexpectedly alter the meaning of the code. More specifically, it looks for if, while, for and for-range statements whose body is a single semicolon, and then analyzes the context of the code (e.g. indentation) in an attempt to determine whether that is intentional.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">if</span> (x &lt; y); { x++; }</code></pre></div> <p>Here the body of the if statement consists of only the semicolon at the end of the first line, and x will be incremented regardless of the condition.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">while</span> ((line = readLine(file)) != NULL); processLine(line);</code></pre></div> <p>As a result of this code, processLine() will only be called once, when the while loop with the empty body exits with line == NULL. The indentation of the code indicates the intention of the programmer.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">if</span> (x &gt;= y); x -= y;</code></pre></div> <p>While the indentation does not imply any nesting, there is simply no valid reason to have an if statement with an empty body (but it can make sense for a loop). So this check issues a warning for the code above.</p> <p>To solve the issue remove the stray semicolon or in case the empty body is intentional, reflect this using code indentation or put the semicolon in a new line. For example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">while</span> (readWhitespace()); Token t = readNextToken();</code></pre></div> <p>Here the second line is indented in a way that suggests that it is meant to be the body of the while loop - whose body is in fact empty, because of the semicolon at the end of the first line.</p> <p>Either remove the indentation from the second line:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">while</span> (readWhitespace()); Token t = readNextToken();</code></pre></div> <p>… or move the semicolon from the end of the first line to a new line:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">while</span> (readWhitespace()) ; Token t = readNextToken();</code></pre></div> <p>In this case the check will assume that you know what you are doing, and will not raise a warning.</p> <p>(Clang-Tidy original name: bugprone-suspicious-semicolon)</p> + + + + Major + + + + + + + true + false + bugprone-suspicious-string-compare + bugprone + + true + Suspicious String Compare + <p>Find suspicious usage of runtime string comparison functions. This check is valid in C and C++.</p> <p>Checks for calls with implicit comparator and proposed to explicitly add it.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">if</span> (strcmp(...)) <span class="co">// Implicitly compare to zero</span> <span class="kw">if</span> (!strcmp(...)) <span class="co">// Won&#39;t warn</span> <span class="kw">if</span> (strcmp(...) != <span class="dv">0</span>) <span class="co">// Won&#39;t warn</span></code></pre></div> <p>Checks that compare function results (i,e, strcmp) are compared to valid constant. The resulting value is</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">&lt; <span class="dv">0</span> when lower than, &gt; <span class="dv">0</span> when greater than, == <span class="dv">0</span> when equals.</code></pre></div> <p>A common mistake is to compare the result to 1 or -1.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">if</span> (strcmp(...) == <span class="dv">-1</span>) <span class="co">// Incorrect usage of the returned value.</span></code></pre></div> <p>Additionally, the check warns if the results value is implicitly cast to a <em>suspicious</em> non-integer type. It’s happening when the returned value is used in a wrong context.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">if</span> (strcmp(...) &lt; <span class="fl">0.</span>) <span class="co">// Incorrect usage of the returned value.</span></code></pre></div> <h5 id="options-79">Options</h5> <p>WarnOnImplicitComparison</p> <p>When true, the check will warn on implicit comparison. true by default.</p> <p>WarnOnLogicalNotComparison</p> <p>When true, the check will warn on logical not comparison. false by default.</p> <p>StringCompareLikeFunctions</p> <p>A string specifying the comma-separated names of the extra string comparison functions. Default is an empty string. The check will detect the following string comparison functions: __builtin_memcmp, __builtin_strcasecmp, __builtin_strcmp, __builtin_strncasecmp, __builtin_strncmp, _mbscmp, _mbscmp_l, _mbsicmp, _mbsicmp_l, _mbsnbcmp, _mbsnbcmp_l, _mbsnbicmp, _mbsnbicmp_l, _mbsncmp, _mbsncmp_l, _mbsnicmp, _mbsnicmp_l, _memicmp, _memicmp_l, _stricmp, _stricmp_l, _strnicmp, _strnicmp_l, _wcsicmp, _wcsicmp_l, _wcsnicmp, _wcsnicmp_l, lstrcmp, lstrcmpi, memcmp, memicmp, strcasecmp, strcmp, strcmpi, stricmp, strncasecmp, strncmp, strnicmp, wcscasecmp, wcscmp, wcsicmp, wcsncmp, wcsnicmp, wmemcmp.</p> <p>(Clang-Tidy original name: bugprone-suspicious-string-compare)</p> + + + + Major + + + + + + + true + false + bugprone-spuriously-wake-up-functions + bugprone + + true + Spuriously Wake Up Functions + <p>Finds cnd_wait, cnd_timedwait, wait, wait_for, or wait_until function calls when the function is not invoked from a loop that checks whether a condition predicate holds or the function has a condition parameter.</p> <p>This check corresponds to the CERT C++ Coding Standard rule <a href="https://wiki.sei.cmu.edu/confluence/display/cplusplus/CON54-CPP.+Wrap+functions+that+can+spuriously+wake+up+in+a+loop">CON54-CPP. Wrap functions that can spuriously wake up in a loop</a>. and CERT C Coding Standard rule <a href="https://wiki.sei.cmu.edu/confluence/display/c/CON36-C.+Wrap+functions+that+can+spuriously+wake+up+in+a+loop">CON36-C. Wrap functions that can spuriously wake up in a loop</a>.</p> <p>(Clang-Tidy original name: bugprone-spuriously-wake-up-functions)</p> + + + + Major + + + + + + + true + false + bugprone-terminating-continue + bugprone + + true + Terminating Continue + <p>Detects do while loops with a condition always evaluating to false that have a continue statement, as this continue terminates the loop effectively.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> f() { <span class="kw">do</span> { <span class="co">// some code</span> <span class="kw">continue</span>; <span class="co">// terminating continue</span> <span class="co">// some other code</span> } <span class="kw">while</span>(<span class="kw">false</span>);</code></pre></div> <p>(Clang-Tidy original name: bugprone-terminating-continue)</p> + + + + Major + + + + + + + true + false + bugprone-throw-keyword-missing + bugprone + + true + Throw Keyword Missing + <p>Warns about a potentially missing throw keyword. If a temporary object is created, but the object’s type derives from (or is the same as) a class that has ‘EXCEPTION’, ‘Exception’ or ‘exception’ in its name, we can assume that the programmer’s intention was to throw that object.</p> <p>Example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> f(<span class="dt">int</span> i) { <span class="kw">if</span> (i &lt; <span class="dv">0</span>) { <span class="co">// Exception is created but is not thrown.</span> std::runtime_error(<span class="st">&quot;Unexpected argument&quot;</span>); } }</code></pre></div> <p>(Clang-Tidy original name: bugprone-throw-keyword-missing)</p> + + + + Major + + + + + + + true + false + bugprone-too-small-loop-variable + bugprone + + true + Too Small Loop Variable + <p>Detects those for loops that have a loop variable with a “too small” type which means this type can’t represent all values which are part of the iteration range.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> main() { <span class="dt">long</span> size = <span class="dv">294967296l</span>; <span class="kw">for</span> (<span class="dt">short</span> i = <span class="dv">0</span>; i &lt; size; ++i) {} }</code></pre></div> <p>This for loop is an infinite loop because the short type can’t represent all values in the [0..size] interval.</p> <p>In a real use case size means a container’s size which depends on the user input.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> doSomething(<span class="dt">const</span> std::vector&amp; items) { <span class="kw">for</span> (<span class="dt">short</span> i = <span class="dv">0</span>; i &lt; items.size(); ++i) {} }</code></pre></div> <p>This algorithm works for small amount of objects, but will lead to freeze for a a larger user input.</p> <p>MagnitudeBitsUpperLimit</p> <p>Upper limit for the magnitude bits of the loop variable. If it’s set the check filters out those catches in which the loop variable’s type has more magnitude bits as the specified upper limit. The default value is 16. For example, if the user sets this option to 31 (bits), then a 32-bit unsigend int is ignored by the check, however a 32-bit int is not (A 32-bit signed int has 31 magnitude bits).</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> main() { <span class="dt">long</span> size = <span class="dv">294967296l</span>; <span class="kw">for</span> (<span class="dt">unsigned</span> i = <span class="dv">0</span>; i &lt; size; ++i) {} <span class="co">// no warning with MagnitudeBitsUpperLimit = 31 on a system where unsigned is 32-bit</span> <span class="kw">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; size; ++i) {} <span class="co">// warning with MagnitudeBitsUpperLimit = 31 on a system where int is 32-bit</span> }</code></pre></div> <p>(Clang-Tidy original name: bugprone-too-small-loop-variable)</p> + + + + Major + + + + + + + true + false + bugprone-use-after-move + bugprone + + true + Use After Move + <p>Warns if an object is used after it has been moved, for example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::string str = <span class="st">&quot;Hello, world!</span><span class="ch">\n</span><span class="st">&quot;</span>; std::vector&lt;std::string&gt; messages; messages.emplace_back(std::move(str)); std::cout &lt;&lt; str;</code></pre></div> <p>The last line will trigger a warning that str is used after it has been moved.</p> <p>The check does not trigger a warning if the object is reinitialized after the move and before the use. For example, no warning will be output for this code:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">messages.emplace_back(std::move(str)); str = <span class="st">&quot;Greetings, stranger!</span><span class="ch">\n</span><span class="st">&quot;</span>; std::cout &lt;&lt; str;</code></pre></div> <p>The check takes control flow into account. A warning is only emitted if the use can be reached from the move. This means that the following code does not produce a warning:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">if</span> (condition) { messages.emplace_back(std::move(str)); } <span class="kw">else</span> { std::cout &lt;&lt; str; }</code></pre></div> <p>On the other hand, the following code does produce a warning:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; <span class="dv">10</span>; ++i) { std::cout &lt;&lt; str; messages.emplace_back(std::move(str)); }</code></pre></div> <p>(The use-after-move happens on the second iteration of the loop.)</p> <p>In some cases, the check may not be able to detect that two branches are mutually exclusive. For example (assuming that i is an int):</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">if</span> (i == <span class="dv">1</span>) { messages.emplace_back(std::move(str)); } <span class="kw">if</span> (i == <span class="dv">2</span>) { std::cout &lt;&lt; str; }</code></pre></div> <p>In this case, the check will erroneously produce a warning, even though it is not possible for both the move and the use to be executed.</p> <p>An erroneous warning can be silenced by reinitializing the object after the move:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">if</span> (i == <span class="dv">1</span>) { messages.emplace_back(std::move(str)); str = <span class="st">&quot;&quot;</span>; } <span class="kw">if</span> (i == <span class="dv">2</span>) { std::cout &lt;&lt; str; }</code></pre></div> <p>Subsections below explain more precisely what exactly the check considers to be a move, use, and reinitialization.</p> <h5 id="unsequenced-moves-uses-and-reinitializations">Unsequenced moves, uses, and reinitializations</h5> <p>In many cases, C++ does not make any guarantees about the order in which sub-expressions of a statement are evaluated. This means that in code like the following, it is not guaranteed whether the use will happen before or after the move:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> f(<span class="dt">int</span> i, std::vector&lt;<span class="dt">int</span>&gt; v); std::vector&lt;<span class="dt">int</span>&gt; v = { <span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span> }; f(v[<span class="dv">1</span>], std::move(v));</code></pre></div> <p>In this kind of situation, the check will note that the use and move are unsequenced.</p> <p>The check will also take sequencing rules into account when reinitializations occur in the same statement as moves or uses. A reinitialization is only considered to reinitialize a variable if it is guaranteed to be evaluated after the move and before the use.</p> <h5 id="move">Move</h5> <p>The check currently only considers calls of std::move on local variables or function parameters. It does not check moves of member variables or global variables.</p> <p>Any call of std::move on a variable is considered to cause a move of that variable, even if the result of std::move is not passed to an rvalue reference parameter.</p> <p>This means that the check will flag a use-after-move even on a type that does not define a move constructor or move assignment operator. This is intentional. Developers may use std::move on such a type in the expectation that the type will add move semantics in the future. If such a std::move has the potential to cause a use-after-move, we want to warn about it even if the type does not implement move semantics yet.</p> <p>Furthermore, if the result of std::move <em>is</em> passed to an rvalue reference parameter, this will always be considered to cause a move, even if the function that consumes this parameter does not move from it, or if it does so only conditionally. For example, in the following situation, the check will assume that a move always takes place:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::vector&lt;std::string&gt; messages; <span class="dt">void</span> f(std::string &amp;&amp;str) { <span class="co">// Only remember the message if it isn&#39;t empty.</span> <span class="kw">if</span> (!str.empty()) { messages.emplace_back(std::move(str)); } } std::string str = <span class="st">&quot;&quot;</span>; f(std::move(str));</code></pre></div> <p>The check will assume that the last line causes a move, even though, in this particular case, it does not. Again, this is intentional.</p> <p>When analyzing the order in which moves, uses and reinitializations happen (see section <a href="#unsequenced-moves-uses-and-reinitializations">Unsequenced moves, uses, and reinitializations</a>), the move is assumed to occur in whichever function the result of the std::move is passed to.</p> <h5 id="use">Use</h5> <p>Any occurrence of the moved variable that is not a reinitialization (see below) is considered to be a use.</p> <p>An exception to this are objects of type std::unique_ptr, std::shared_ptr and std::weak_ptr, which have defined move behavior (objects of these classes are guaranteed to be empty after they have been moved from). Therefore, an object of these classes will only be considered to be used if it is dereferenced, i.e. if operator*, operator-&gt; or operator[] (in the case of std::unique_ptr<T []>) is called on it.</p> <p>If multiple uses occur after a move, only the first of these is flagged.</p> <h5 id="reinitialization">Reinitialization</h5> <p>The check considers a variable to be reinitialized in the following cases:</p> <ul> <li>The variable occurs on the left-hand side of an assignment.</li> <li>The variable is passed to a function as a non-const pointer or non-const lvalue reference. (It is assumed that the variable may be an out-parameter for the function.)</li> <li>clear() or assign() is called on the variable and the variable is of one of the standard container types basic_string, vector, deque, forward_list, list, set, map, multiset, multimap, unordered_set, unordered_map, unordered_multiset, unordered_multimap.</li> <li>reset() is called on the variable and the variable is of type std::unique_ptr, std::shared_ptr or std::weak_ptr.</li> <li>A member function marked with the [[clang::reinitializes]] attribute is called on the variable.</li> </ul> <p>If the variable in question is a struct and an individual member variable of that struct is written to, the check does not consider this to be a reinitialization – even if, eventually, all member variables of the struct are written to. For example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> S { std::string str; <span class="dt">int</span> i; }; S s = { <span class="st">&quot;Hello, world!</span><span class="ch">\n</span><span class="st">&quot;</span>, <span class="dv">42</span> }; S s_other = std::move(s); s.str = <span class="st">&quot;Lorem ipsum&quot;</span>; s.i = <span class="dv">99</span>;</code></pre></div> <p>The check will not consider s to be reinitialized after the last line; instead, the line that assigns to s.str will be flagged as a use-after-move. This is intentional as this pattern of reinitializing a struct is error-prone. For example, if an additional member variable is added to S, it is easy to forget to add the reinitialization for this additional member. Instead, it is safer to assign to the entire struct in one go, and this will also avoid the use-after-move warning.</p> <p>(Clang-Tidy original name: bugprone-use-after-move)</p> + + + + Major + + + + + + + true + false + bugprone-undelegated-constructor + bugprone + + true + Undelegated Constructor + <p>Finds creation of temporary objects in constructors that look like a function call to another constructor of the same class.</p> <p>The user most likely meant to use a delegating constructor or base class initializer.</p> <p>(Clang-Tidy original name: bugprone-undelegated-constructor)</p> + + + + Major + + + + + + + true + false + bugprone-undefined-memory-manipulation + bugprone + + true + Undefined Memory Manipulation + <p>Finds calls of memory manipulation functions memset(), memcpy() and memmove() on not TriviallyCopyable objects resulting in undefined behavior.</p> <p>(Clang-Tidy original name: bugprone-undefined-memory-manipulation)</p> + + + + Major + + + + + + + true + false + bugprone-unused-raii + bugprone + + true + Unused Raii + <p>Finds temporaries that look like RAII objects.</p> <p>The canonical example for this is a scoped lock.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">{ scoped_lock(&amp;global_mutex); critical_section(); }</code></pre></div> <p>The destructor of the scoped_lock is called before the critical_section is entered, leaving it unprotected.</p> <p>We apply a number of heuristics to reduce the false positive count of this check:</p> <ul> <li>Ignore code expanded from macros. Testing frameworks make heavy use of this.</li> <li>Ignore types with trivial destructors. They are very unlikely to be RAII objects and there’s no difference when they are deleted.</li> <li>Ignore objects at the end of a compound statement (doesn’t change behavior).</li> <li>Ignore objects returned from a call.</li> </ul> <p>(Clang-Tidy original name: bugprone-unused-raii)</p> + + + + Major + + + + + + + true + false + bugprone-unused-return-value + bugprone + + true + Unused Return Value + <p>Warns on unused function return values. The checked functions can be configured.</p> <h5 id="options-23">Options</h5> <p>CheckedFunctions</p> <p>Semicolon-separated list of functions to check. Defaults to ::std::async;::std::launder;::std::remove;::std::remove_if;::std::unique;::std::unique_ptr::release;::std::basic_string::empty;::std::vector::empty. This means that the calls to following functions are checked by default:</p> <ul> <li>std::async(). Not using the return value makes the call synchronous.</li> <li>std::launder(). Not using the return value usually means that the function interface was misunderstood by the programmer. Only the returned pointer is “laundered”, not the argument.</li> <li>std::remove(), std::remove_if() and std::unique(). The returned iterator indicates the boundary between elements to keep and elements to be removed. Not using the return value means that the information about which elements to remove is lost.</li> <li>std::unique_ptr::release(). Not using the return value can lead to resource leaks if the same pointer isn’t stored anywhere else. Often, ignoring the release() return value indicates that the programmer confused the function with reset().</li> <li>std::basic_string::empty() and std::vector::empty(). Not using the return value often indicates that the programmer confused the function with clear().</li> </ul> <p>(Clang-Tidy original name: bugprone-unused-return-value)</p> + + + + Major + + + + + + + true + false + bugprone-unhandled-self-assignment + bugprone + + true + Unhandled Self Assignment + <p>cert-oop54-cpp redirects here as an alias for this check. For the CERT alias, the WarnOnlyIfThisHasSuspiciousField option is set to false.</p> <p>Finds user-defined copy assignment operators which do not protect the code against self-assignment either by checking self-assignment explicitly or using the copy-and-swap or the copy-and-move method.</p> <p>By default, this check searches only those classes which have any pointer or C array field to avoid false positives. In case of a pointer or a C array, it’s likely that self-copy assignment breaks the object if the copy assignment operator was not written with care.</p> <p>See also: <a href="https://wiki.sei.cmu.edu/confluence/display/cplusplus/OOP54-CPP.+Gracefully+handle+self-copy+assignment">OOP54-CPP. Gracefully handle self-copy assignment</a></p> <p>A copy assignment operator must prevent that self-copy assignment ruins the object state. A typical use case is when the class has a pointer field and the copy assignment operator first releases the pointed object and then tries to assign it:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> T { <span class="dt">int</span>* p; <span class="kw">public</span>: T(<span class="dt">const</span> T &amp;rhs) : p(rhs.p ? <span class="kw">new</span> <span class="dt">int</span>(*rhs.p) : <span class="kw">nullptr</span>) {} ~T() { <span class="kw">delete</span> p; } <span class="co">// ...</span> T&amp; <span class="kw">operator</span>=(<span class="dt">const</span> T &amp;rhs) { <span class="kw">delete</span> p; p = <span class="kw">new</span> <span class="dt">int</span>(*rhs.p); <span class="kw">return</span> *<span class="kw">this</span>; } };</code></pre></div> <p>There are two common C++ patterns to avoid this problem. The first is the self-assignment check:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> T { <span class="dt">int</span>* p; <span class="kw">public</span>: T(<span class="dt">const</span> T &amp;rhs) : p(rhs.p ? <span class="kw">new</span> <span class="dt">int</span>(*rhs.p) : <span class="kw">nullptr</span>) {} ~T() { <span class="kw">delete</span> p; } <span class="co">// ...</span> T&amp; <span class="kw">operator</span>=(<span class="dt">const</span> T &amp;rhs) { <span class="kw">if</span>(<span class="kw">this</span> == &amp;rhs) <span class="kw">return</span> *<span class="kw">this</span>; <span class="kw">delete</span> p; p = <span class="kw">new</span> <span class="dt">int</span>(*rhs.p); <span class="kw">return</span> *<span class="kw">this</span>; } };</code></pre></div> <p>The second one is the copy-and-swap method when we create a temporary copy (using the copy constructor) and then swap this temporary object with this:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> T { <span class="dt">int</span>* p; <span class="kw">public</span>: T(<span class="dt">const</span> T &amp;rhs) : p(rhs.p ? <span class="kw">new</span> <span class="dt">int</span>(*rhs.p) : <span class="kw">nullptr</span>) {} ~T() { <span class="kw">delete</span> p; } <span class="co">// ...</span> <span class="dt">void</span> swap(T &amp;rhs) { <span class="kw">using</span> std::swap; swap(p, rhs.p); } T&amp; <span class="kw">operator</span>=(<span class="dt">const</span> T &amp;rhs) { T(rhs).swap(*<span class="kw">this</span>); <span class="kw">return</span> *<span class="kw">this</span>; } };</code></pre></div> <p>There is a third pattern which is less common. Let’s call it the copy-and-move method when we create a temporary copy (using the copy constructor) and then move this temporary object into this (needs a move assignment operator):</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> T { <span class="dt">int</span>* p; <span class="kw">public</span>: T(<span class="dt">const</span> T &amp;rhs) : p(rhs.p ? <span class="kw">new</span> <span class="dt">int</span>(*rhs.p) : <span class="kw">nullptr</span>) {} ~T() { <span class="kw">delete</span> p; } <span class="co">// ...</span> T&amp; <span class="kw">operator</span>=(<span class="dt">const</span> T &amp;rhs) { T t = rhs; *<span class="kw">this</span> = std::move(t); <span class="kw">return</span> *<span class="kw">this</span>; } T&amp; <span class="kw">operator</span>=(T &amp;&amp;rhs) { p = rhs.p; rhs.p = <span class="kw">nullptr</span>; <span class="kw">return</span> *<span class="kw">this</span>; } };</code></pre></div> <p>WarnOnlyIfThisHasSuspiciousField</p> <p>When true, the check will warn only if the container class of the copy assignment operator has any suspicious fields (pointer or C array). This option is set to true by default.</p> <p>(Clang-Tidy original name: bugprone-unhandled-self-assignment)</p> + + + + Major + + + + + + + true + false + bugprone-virtual-near-miss + bugprone + + true + Virtual Near Miss + <p>Warn if a function is a near miss (ie. the name is very similar and the function signature is the same) to a virtual function from a base class.</p> <p>Example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> Base { <span class="kw">virtual</span> <span class="dt">void</span> func(); }; <span class="kw">struct</span> Derived : Base { <span class="kw">virtual</span> funk(); <span class="co">// warning: &#39;Derived::funk&#39; has a similar name and the same signature as virtual method &#39;Base::func&#39;; did you mean to override it?</span> };</code></pre></div> <p>(Clang-Tidy original name: bugprone-virtual-near-miss)</p> + + + + Major + + + + + + + true + false + concurrency-mt-unsafe + concurrency + + true + Mt Unsafe + <p>Checks for some thread-unsafe functions against a black list of known-to-be-unsafe functions. Usually they access static variables without synchronization (e.g. gmtime(3)) or utilize signals in a racy way. The set of functions to check is specified with the FunctionSet option.</p> <p>Note that using some thread-unsafe functions may be still valid in concurrent programming if only a single thread is used (e.g. setenv(3)), however, some functions may track a state in global variables which would be clobbered by subsequent (non-parallel, but concurrent) calls to a related function. E.g. the following code suffers from unprotected accesses to a global state:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// getnetent(3) maintains global state with DB connection, etc.</span> <span class="co">// If a concurrent green thread calls getnetent(3), the global state is corrupted.</span> netent = getnetent(); yield(); netent = getnetent();</code></pre></div> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">tm = gmtime(timep); <span class="co">// uses a global buffer</span> sleep(<span class="dv">1</span>); <span class="co">// implementation may use SIGALRM</span></code></pre></div> <p>FunctionSet</p> <p>Specifies which functions in libc should be considered thread-safe, possible values are posix, glibc, or any.</p> <p>posix means POSIX defined thread-unsafe functions. POSIX.1-2001 in “2.9.1 Thread-Safety” defines that all functions specified in the standard are thread-safe except a predefined list of thread-unsafe functions.</p> <p>Glibc defines some of them as thread-safe (e.g. dirname(3)), but adds non-POSIX thread-unsafe ones (e.g. getopt_long(3)). Glibc’s list is compiled from GNU web documentation with a search for MT-Safe tag: <a href="https://www.gnu.org/software/libc/manual/html_node/POSIX-Safety-Concepts.html" class="uri">https://www.gnu.org/software/libc/manual/html_node/POSIX-Safety-Concepts.html</a></p> <p>If you want to identify thread-unsafe API for at least one libc or unsure which libc will be used, use any (default).</p> <p>(Clang-Tidy original name: concurrency-mt-unsafe)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-avoid-c-arrays + cppcoreguidelines + + true + Avoid C Arrays + <p>The cppcoreguidelines-avoid-c-arrays check is an alias, please see <a href="modernize-avoid-c-arrays.html">modernize-avoid-c-arrays</a> for more information.</p> <p>(Clang-Tidy original name: cppcoreguidelines-avoid-c-arrays)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-avoid-goto + cppcoreguidelines + + true + Avoid Goto + <p>The usage of goto for control flow is error prone and should be replaced with looping constructs. Only forward jumps in nested loops are accepted.</p> <p>This check implements <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es76-avoid-goto">ES.76</a> from the CppCoreGuidelines and <a href="http://www.codingstandard.com/rule/6-3-1-ensure-that-the-labels-for-a-jump-statement-or-a-switch-condition-appear-later-in-the-same-or-an-enclosing-block/">6.3.1 from High Integrity C++</a>.</p> <p>For more information on why to avoid programming with goto you can read the famous paper <a href="https://www.cs.utexas.edu/users/EWD/ewd02xx/EWD215.PDF">A Case against the GO TO Statement.</a>.</p> <p>The check diagnoses goto for backward jumps in every language mode. These should be replaced with C/C++ looping constructs.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Bad, handwritten for loop.</span> <span class="dt">int</span> i = <span class="dv">0</span>; <span class="co">// Jump label for the loop</span> loop_start: do_some_operation(); <span class="kw">if</span> (i &lt; <span class="dv">100</span>) { ++i; <span class="kw">goto</span> loop_start; } <span class="co">// Better</span> <span class="kw">for</span>(<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; <span class="dv">100</span>; ++i) do_some_operation();</code></pre></div> <p>Modern C++ needs goto only to jump out of nested loops.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">for</span>(<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; <span class="dv">100</span>; ++i) { <span class="kw">for</span>(<span class="dt">int</span> j = <span class="dv">0</span>; j &lt; <span class="dv">100</span>; ++j) { <span class="kw">if</span> (i * j &gt; <span class="dv">500</span>) <span class="kw">goto</span> early_exit; } } early_exit: some_operation();</code></pre></div> <p>All other uses of goto are diagnosed in C++.</p> <p>(Clang-Tidy original name: cppcoreguidelines-avoid-goto)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-avoid-magic-numbers + cppcoreguidelines + + true + Avoid Magic Numbers + <p>The cppcoreguidelines-avoid-magic-numbers check is an alias, please see <a href="readability-magic-numbers.html">readability-magic-numbers</a> for more information.</p> <p>(Clang-Tidy original name: cppcoreguidelines-avoid-magic-numbers)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-avoid-non-const-global-variables + cppcoreguidelines + + true + Avoid Non Const Global Variables + <p>Finds non-const global variables as described in <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Ri-global">I.2 of C++ Core Guidelines</a> . As <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rr-global">R.6 of C++ Core Guidelines</a> is a duplicate of rule I.2 it also covers that rule.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">char</span> a; <span class="co">// Warns!</span> <span class="dt">const</span> <span class="dt">char</span> b = <span class="dv">0</span>; <span class="kw">namespace</span> some_namespace { <span class="dt">char</span> c; <span class="co">// Warns!</span> <span class="dt">const</span> <span class="dt">char</span> d = <span class="dv">0</span>; } <span class="dt">char</span> * c_ptr1 = &amp;some_namespace::c; <span class="co">// Warns!</span> <span class="dt">char</span> *<span class="dt">const</span> c_const_ptr = &amp;some_namespace::c; <span class="co">// Warns!</span> <span class="dt">char</span> &amp; c_reference = some_namespace::c; <span class="co">// Warns!</span> <span class="kw">class</span> Foo <span class="co">// No Warnings inside Foo, only namespace scope is covered</span> { <span class="kw">public</span>: <span class="dt">char</span> e = <span class="dv">0</span>; <span class="dt">const</span> <span class="dt">char</span> f = <span class="dv">0</span>; <span class="kw">protected</span>: <span class="dt">char</span> g = <span class="dv">0</span>; <span class="kw">private</span>: <span class="dt">char</span> h = <span class="dv">0</span>; };</code></pre></div> <p>Variables: a, c, c_ptr1, c_ptr2, c_const_ptr and c_reference, will all generate warnings since they are either: a globally accessible variable and non-const, a pointer or reference providing global access to non-const data or both.</p> <p>(Clang-Tidy original name: cppcoreguidelines-avoid-non-const-global-variables)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-c-copy-assignment-signature + cppcoreguidelines + + true + C Copy Assignment Signature + <p>The cppcoreguidelines-c-copy-assignment-signature check is an alias, please see <a href="misc-unconventional-assign-operator.html">misc-unconventional-assign-operator</a> for more information.</p> <p>(Clang-Tidy original name: cppcoreguidelines-c-copy-assignment-signature)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-explicit-virtual-functions + cppcoreguidelines + + true + Explicit Virtual Functions + <p>The cppcoreguidelines-explicit-virtual-functions check is an alias, please see <a href="modernize-use-override.html">modernize-use-override</a> for more information.</p> <p>(Clang-Tidy original name: cppcoreguidelines-explicit-virtual-functions)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-interfaces-global-init + cppcoreguidelines + + true + Interfaces Global Init + <p>This check flags initializers of globals that access extern objects, and therefore can lead to order-of-initialization problems.</p> <p>This rule is part of the “Interfaces” profile of the C++ Core Guidelines, see <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Ri-global-init" class="uri">https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Ri-global-init</a></p> <p>Note that currently this does not flag calls to non-constexpr functions, and therefore globals could still be accessed from functions themselves.</p> <p>(Clang-Tidy original name: cppcoreguidelines-interfaces-global-init)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-init-variables + cppcoreguidelines + + true + Init Variables + <p>Checks whether there are local variables that are declared without an initial value. These may lead to unexpected behaviour if there is a code path that reads the variable before assigning to it.</p> <p>Only integers, booleans, floats, doubles and pointers are checked. The fix option initializes all detected values with the value of zero. An exception is float and double types, which are initialized to NaN.</p> <p>As an example a function that looks like this:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> function() { <span class="dt">int</span> x; <span class="dt">char</span> *txt; <span class="dt">double</span> d; <span class="co">// Rest of the function.</span> }</code></pre></div> <p>Would be rewritten to look like this:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#include &lt;math.h&gt;</span> <span class="dt">void</span> function() { <span class="dt">int</span> x = <span class="dv">0</span>; <span class="dt">char</span> *txt = <span class="kw">nullptr</span>; <span class="dt">double</span> d = NAN; <span class="co">// Rest of the function.</span> }</code></pre></div> <h5 id="options-57">Options</h5> <p>IncludeStyle</p> <p>A string specifying which include-style is used, llvm or google. Default is llvm.</p> <p>MathHeader</p> <p>A string specifying the header to include to get the definition of NAN. Default is <math.h>.</p> <p>(Clang-Tidy original name: cppcoreguidelines-init-variables)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-macro-usage + cppcoreguidelines + + true + Macro Usage + <p>Finds macro usage that is considered problematic because better language constructs exist for the task.</p> <p>The relevant sections in the C++ Core Guidelines are <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#enum1-prefer-enumerations-over-macros">Enum.1</a>, <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es30-dont-use-macros-for-program-text-manipulation">ES.30</a>, <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es31-dont-use-macros-for-constants-or-functions">ES.31</a> and <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es33-if-you-must-use-macros-give-them-unique-names">ES.33</a>.</p> <h5 id="options-3">Options</h5> <p>AllowedRegexp</p> <p>A regular expression to filter allowed macros. For example DEBUG<em>|LIBTORRENT</em>|TORRENT<em>|UNI</em> could be applied to filter libtorrent. Default value is ^DEBUG_*.</p> <p>CheckCapsOnly</p> <p>Boolean flag to warn on all macros except those with CAPS_ONLY names. This option is intended to ease introduction of this check into older code bases. Default value is false.</p> <p>IgnoreCommandLineMacros</p> <p>Boolean flag to toggle ignoring command-line-defined macros. Default value is true.</p> <p>(Clang-Tidy original name: cppcoreguidelines-macro-usage)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-narrowing-conversions + cppcoreguidelines + + true + Narrowing Conversions + <p>Checks for silent narrowing conversions, e.g: int i = 0; i += 0.1;. While the issue is obvious in this former example, it might not be so in the following: void MyClass::f(double d) { int_member_ += d; }.</p> <p>This rule is part of the “Expressions and statements” profile of the C++ Core Guidelines, corresponding to rule ES.46. See</p> <p><a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#es46-avoid-lossy-narrowing-truncating-arithmetic-conversions" class="uri">https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#es46-avoid-lossy-narrowing-truncating-arithmetic-conversions</a>.</p> <p>We enforce only part of the guideline, more specifically, we flag narrowing conversions from:</p> <ul> <li>an integer to a narrower integer (e.g. char to unsigned char),</li> <li>an integer to a narrower floating-point (e.g. uint64_t to float),</li> <li>a floating-point to an integer (e.g. double to int),</li> <li>a floating-point to a narrower floating-point (e.g. double to float) if WarnOnFloatingPointNarrowingConversion Option is set.</li> </ul> <p>This check will flag:</p> <ul> <li>All narrowing conversions that are not marked by an explicit cast (c-style or static_cast). For example: int i = 0; i += 0.1;, void f(int); f(0.1);,</li> <li>All applications of binary operators with a narrowing conversions. For example: int i; i+= 0.1;.</li> </ul> <h5 id="options-8">Options</h5> <p>WarnOnFloatingPointNarrowingConversion</p> <p>When true, the check will warn on narrowing floating point conversion (e.g. double to float). true by default.</p> <p>PedanticMode</p> <p>When true, the check will warn on assigning a floating point constant to an integer value even if the floating point value is exactly representable in the destination type (e.g. int i = 1.0;). false by default.</p> <h5 id="faq">FAQ</h5> <ul> <li>What does “narrowing conversion from ‘int’ to ‘float’” mean?</li> </ul> <p>An IEEE754 Floating Point number can represent all integer values in the range [-2^PrecisionBits, 2^PrecisionBits] where PrecisionBits is the number of bits in the mantissa.</p> <p>For float this would be [-2^23, 2^23], where int can represent values in the range [-2^31, 2^31-1].</p> <ul> <li>What does “implementation-defined” mean?</li> </ul> <p>You may have encountered messages like “narrowing conversion from ‘unsigned int’ to signed type ‘int’ is implementation-defined”. The C/C++ standard does not mandate two’s complement for signed integers, and so the compiler is free to define what the semantics are for converting an unsigned integer to signed integer. Clang’s implementation uses the two’s complement format.</p> <p>(Clang-Tidy original name: cppcoreguidelines-narrowing-conversions)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-no-malloc + cppcoreguidelines + + true + No Malloc + <p>This check handles C-Style memory management using malloc(), realloc(), calloc() and free(). It warns about its use and tries to suggest the use of an appropriate RAII object. Furthermore, it can be configured to check against a user-specified list of functions that are used for memory management (e.g. posix_memalign()). See <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rr-mallocfree">C++ Core Guidelines</a>.</p> <p>There is no attempt made to provide fix-it hints, since manual resource management isn’t easily transformed automatically into RAII.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Warns each of the following lines.</span> <span class="co">// Containers like std::vector or std::string should be used.</span> <span class="dt">char</span>* some_string = (<span class="dt">char</span>*) malloc(<span class="kw">sizeof</span>(<span class="dt">char</span>) * <span class="dv">20</span>); <span class="dt">char</span>* some_string = (<span class="dt">char</span>*) realloc(<span class="kw">sizeof</span>(<span class="dt">char</span>) * <span class="dv">30</span>); free(some_string); <span class="dt">int</span>* int_array = (<span class="dt">int</span>*) calloc(<span class="dv">30</span>, <span class="kw">sizeof</span>(<span class="dt">int</span>)); <span class="co">// Rather use a smartpointer or stack variable.</span> <span class="kw">struct</span> some_struct* s = (<span class="kw">struct</span> some_struct*) malloc(<span class="kw">sizeof</span>(<span class="kw">struct</span> some_struct));</code></pre></div> <h5 id="options-52">Options</h5> <p>Allocations</p> <p>Semicolon-separated list of fully qualified names of memory allocation functions. Defaults to ::malloc;::calloc.</p> <p>Deallocations</p> <p>Semicolon-separated list of fully qualified names of memory allocation functions. Defaults to ::free.</p> <p>Reallocations</p> <p>Semicolon-separated list of fully qualified names of memory allocation functions. Defaults to ::realloc.</p> <p>(Clang-Tidy original name: cppcoreguidelines-no-malloc)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-non-private-member-variables-in-classes + cppcoreguidelines + + true + Non Private Member Variables In Classes + <p>The cppcoreguidelines-non-private-member-variables-in-classes check is an alias, please see <a href="misc-non-private-member-variables-in-classes.html">misc-non-private-member-variables-in-classes</a> for more information.</p> <p>(Clang-Tidy original name: cppcoreguidelines-non-private-member-variables-in-classes)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-owning-memory + cppcoreguidelines + + true + Owning Memory + <p>This check implements the type-based semantics of gsl::owner<T*>, which allows static analysis on code, that uses raw pointers to handle resources like dynamic memory, but won’t introduce RAII concepts.</p> <p>The relevant sections in the <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md">C++ Core Guidelines</a> are I.11, C.33, R.3 and GSL.Views The definition of a gsl::owner<T*> is straight forward</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">namespace</span> gsl { <span class="kw">template</span> &lt;<span class="kw">typename</span> T&gt; owner = T; }</code></pre></div> <p>It is therefore simple to introduce the owner even without using an implementation of the <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gsl-guideline-support-library">Guideline Support Library</a>.</p> <p>All checks are purely type based and not (yet) flow sensitive.</p> <p>The following examples will demonstrate the correct and incorrect initializations of owners, assignment is handled the same way. Note that both new and malloc()-like resource functions are considered to produce resources.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Creating an owner with factory functions is checked.</span> gsl::owner&lt;<span class="dt">int</span>*&gt; function_that_returns_owner() { <span class="kw">return</span> gsl::owner&lt;<span class="dt">int</span>*&gt;(<span class="kw">new</span> <span class="dt">int</span>(<span class="dv">42</span>)); } <span class="co">// Dynamic memory must be assigned to an owner</span> <span class="dt">int</span>* Something = <span class="kw">new</span> <span class="dt">int</span>(<span class="dv">42</span>); <span class="co">// BAD, will be caught</span> gsl::owner&lt;<span class="dt">int</span>*&gt; Owner = <span class="kw">new</span> <span class="dt">int</span>(<span class="dv">42</span>); <span class="co">// Good</span> gsl::owner&lt;<span class="dt">int</span>*&gt; Owner = <span class="kw">new</span> <span class="dt">int</span>[<span class="dv">42</span>]; <span class="co">// Good as well</span> <span class="co">// Returned owner must be assigned to an owner</span> <span class="dt">int</span>* Something = function_that_returns_owner(); <span class="co">// Bad, factory function</span> gsl::owner&lt;<span class="dt">int</span>*&gt; Owner = function_that_returns_owner(); <span class="co">// Good, result lands in owner</span> <span class="co">// Something not a resource or owner should not be assigned to owners</span> <span class="dt">int</span> Stack = <span class="dv">42</span>; gsl::owner&lt;<span class="dt">int</span>*&gt; Owned = &amp;Stack; <span class="co">// Bad, not a resource assigned</span></code></pre></div> <p>In the case of dynamic memory as resource, only gsl::owner<T*> variables are allowed to be deleted.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Example Bad, non-owner as resource handle, will be caught.</span> <span class="dt">int</span>* NonOwner = <span class="kw">new</span> <span class="dt">int</span>(<span class="dv">42</span>); <span class="co">// First warning here, since new must land in an owner</span> <span class="kw">delete</span> NonOwner; <span class="co">// Second warning here, since only owners are allowed to be deleted</span> <span class="co">// Example Good, Ownership correctly stated</span> gsl::owner&lt;<span class="dt">int</span>*&gt; Owner = <span class="kw">new</span> <span class="dt">int</span>(<span class="dv">42</span>); <span class="co">// Good</span> <span class="kw">delete</span> Owner; <span class="co">// Good as well, statically enforced, that only owners get deleted</span></code></pre></div> <p>The check will furthermore ensure, that functions, that expect a gsl::owner<T*> as argument get called with either a gsl::owner<T*> or a newly created resource.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> expects_owner(gsl::owner&lt;<span class="dt">int</span>*&gt; o) { <span class="kw">delete</span> o; } <span class="co">// Bad Code</span> <span class="dt">int</span> NonOwner = <span class="dv">42</span>; expects_owner(&amp;NonOwner); <span class="co">// Bad, will get caught</span> <span class="co">// Good Code</span> gsl::owner&lt;<span class="dt">int</span>*&gt; Owner = <span class="kw">new</span> <span class="dt">int</span>(<span class="dv">42</span>); expects_owner(Owner); <span class="co">// Good</span> expects_owner(<span class="kw">new</span> <span class="dt">int</span>(<span class="dv">42</span>)); <span class="co">// Good as well, recognized created resource</span> <span class="co">// Port legacy code for better resource-safety</span> gsl::owner&lt;FILE*&gt; File = fopen(<span class="st">&quot;my_file.txt&quot;</span>, <span class="st">&quot;rw+&quot;</span>); FILE* BadFile = fopen(<span class="st">&quot;another_file.txt&quot;</span>, <span class="st">&quot;w&quot;</span>); <span class="co">// Bad, warned</span> <span class="co">// ... use the file</span> fclose(File); <span class="co">// Ok, File is annotated as &#39;owner&lt;&gt;&#39;</span> fclose(BadFile); <span class="co">// BadFile is not an &#39;owner&lt;&gt;&#39;, will be warned</span></code></pre></div> <h5 id="options-76">Options</h5> <p>LegacyResourceProducers</p> <p>Semicolon-separated list of fully qualified names of legacy functions that create resources but cannot introduce gsl::owner&lt;&gt;. Defaults to ::malloc;::aligned_alloc;::realloc;::calloc;::fopen;::freopen;::tmpfile.</p> <p>LegacyResourceConsumers</p> <p>Semicolon-separated list of fully qualified names of legacy functions expecting resource owners as pointer arguments but cannot introduce gsl::owner&lt;&gt;. Defaults to ::free;::realloc;::freopen;::fclose.</p> <h5 id="limitations-4">Limitations</h5> <p>Using gsl::owner<T*> in a typedef or alias is not handled correctly.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">using</span> heap_int = gsl::owner&lt;<span class="dt">int</span>*&gt;; heap_int allocated = <span class="kw">new</span> <span class="dt">int</span>(<span class="dv">42</span>); <span class="co">// False positive!</span></code></pre></div> <p>The gsl::owner<T*> is declared as a templated type alias. In template functions and classes, like in the example below, the information of the type aliases gets lost. Therefore using gsl::owner<T*> in a heavy templated code base might lead to false positives.</p> <p>Known code constructs that do not get diagnosed correctly are:</p> <ul> <li>std::exchange</li> <li>std::vector<gsl::owner<T*>&gt;</li> </ul> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// This template function works as expected. Type information doesn&#39;t get lost.</span> <span class="kw">template</span> &lt;<span class="kw">typename</span> T&gt; <span class="dt">void</span> delete_owner(gsl::owner&lt;T*&gt; owned_object) { <span class="kw">delete</span> owned_object; <span class="co">// Everything alright</span> } gsl::owner&lt;<span class="dt">int</span>*&gt; function_that_returns_owner() { <span class="kw">return</span> gsl::owner&lt;<span class="dt">int</span>*&gt;(<span class="kw">new</span> <span class="dt">int</span>(<span class="dv">42</span>)); } <span class="co">// Type deduction does not work for auto variables.</span> <span class="co">// This is caught by the check and will be noted accordingly.</span> <span class="kw">auto</span> OwnedObject = function_that_returns_owner(); <span class="co">// Type of OwnedObject will be int*</span> <span class="co">// Problematic function template that looses the typeinformation on owner</span> <span class="kw">template</span> &lt;<span class="kw">typename</span> T&gt; <span class="dt">void</span> bad_template_function(T some_object) { <span class="co">// This line will trigger the warning, that a non-owner is assigned to an owner</span> gsl::owner&lt;T*&gt; new_owner = some_object; } <span class="co">// Calling the function with an owner still yields a false positive.</span> bad_template_function(gsl::owner&lt;<span class="dt">int</span>*&gt;(<span class="kw">new</span> <span class="dt">int</span>(<span class="dv">42</span>))); <span class="co">// The same issue occurs with templated classes like the following.</span> <span class="kw">template</span> &lt;<span class="kw">typename</span> T&gt; <span class="kw">class</span> OwnedValue { <span class="kw">public</span>: <span class="dt">const</span> T getValue() <span class="dt">const</span> { <span class="kw">return</span> _val; } <span class="kw">private</span>: T _val; }; <span class="co">// Code, that yields a false positive.</span> OwnedValue&lt;gsl::owner&lt;<span class="dt">int</span>*&gt;&gt; Owner(<span class="kw">new</span> <span class="dt">int</span>(<span class="dv">42</span>)); <span class="co">// Type deduction yield T -&gt; int *</span> <span class="co">// False positive, getValue returns int* and not gsl::owner&lt;int*&gt;</span> gsl::owner&lt;<span class="dt">int</span>*&gt; OwnedInt = Owner.getValue();</code></pre></div> <p>Another limitation of the current implementation is only the type based checking. Suppose you have code like the following:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Two owners with assigned resources</span> gsl::owner&lt;<span class="dt">int</span>*&gt; Owner1 = <span class="kw">new</span> <span class="dt">int</span>(<span class="dv">42</span>); gsl::owner&lt;<span class="dt">int</span>*&gt; Owner2 = <span class="kw">new</span> <span class="dt">int</span>(<span class="dv">42</span>); Owner2 = Owner1; <span class="co">// Conceptual Leak of initial resource of Owner2!</span> Owner1 = <span class="kw">nullptr</span>;</code></pre></div> <p>The semantic of a gsl::owner<T*> is mostly like a std::unique_ptr<T>, therefore assignment of two gsl::owner<T*> is considered a move, which requires that the resource Owner2 must have been released before the assignment. This kind of condition could be caught in later improvements of this check with flowsensitive analysis. Currently, the Clang Static Analyzer catches this bug for dynamic memory, but not for general types of resources.</p> <p>(Clang-Tidy original name: cppcoreguidelines-owning-memory)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-pro-bounds-array-to-pointer-decay + cppcoreguidelines + + true + Pro Bounds Array To Pointer Decay + <p>This check flags all array to pointer decays.</p> <p>Pointers should not be used as arrays. span<T> is a bounds-checked, safe alternative to using pointers to access arrays.</p> <p>This rule is part of the “Bounds safety” profile of the C++ Core Guidelines, see <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-bounds-decay" class="uri">https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-bounds-decay</a>.</p> <p>(Clang-Tidy original name: cppcoreguidelines-pro-bounds-array-to-pointer-decay)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-pro-bounds-constant-array-index + cppcoreguidelines + + true + Pro Bounds Constant Array Index + <p>This check flags all array subscript expressions on static arrays and std::arrays that either do not have a constant integer expression index or are out of bounds (for std::array). For out-of-bounds checking of static arrays, see the -Warray-bounds Clang diagnostic.</p> <p>This rule is part of the “Bounds safety” profile of the C++ Core Guidelines, see <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-bounds-arrayindex" class="uri">https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-bounds-arrayindex</a>.</p> <h5 id="options-62">Options</h5> <p>GslHeader</p> <p>The check can generate fixes after this option has been set to the name of the include file that contains gsl::at(), e.g. “gsl/gsl.h”.</p> <p>IncludeStyle</p> <p>A string specifying which include-style is used, llvm or google. Default is llvm.</p> <p>(Clang-Tidy original name: cppcoreguidelines-pro-bounds-constant-array-index)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-pro-bounds-pointer-arithmetic + cppcoreguidelines + + true + Pro Bounds Pointer Arithmetic + <p>This check flags all usage of pointer arithmetic, because it could lead to an invalid pointer. Subtraction of two pointers is not flagged by this check.</p> <p>Pointers should only refer to single objects, and pointer arithmetic is fragile and easy to get wrong. span<T> is a bounds-checked, safe type for accessing arrays of data.</p> <p>This rule is part of the “Bounds safety” profile of the C++ Core Guidelines, see <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-bounds-arithmetic" class="uri">https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-bounds-arithmetic</a>.</p> <p>(Clang-Tidy original name: cppcoreguidelines-pro-bounds-pointer-arithmetic)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-prefer-member-initializer + cppcoreguidelines + + true + Prefer Member Initializer + <p>Finds member initializations in the constructor body which can be converted into member initializers of the constructor instead. This not only improves the readability of the code but also positively affects its performance. Class-member assignments inside a control statement or following the first control statement are ignored.</p> <p>This check implements <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#c49-prefer-initialization-to-assignment-in-constructors">C.49</a> from the CppCoreGuidelines.</p> <p>If the language version is C++ 11 or above, the constructor is the default constructor of the class, the field is not a bitfield (only in case of earlier language version than C++ 20), furthermore the assigned value is a literal, negated literal or enum constant then the preferred place of the initialization is at the class member declaration.</p> <p>This latter rule is <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#c48-prefer-in-class-initializers-to-member-initializers-in-constructors-for-constant-initializers">C.48</a> from CppCoreGuidelines.</p> <p>Please note, that this check does not enforce this latter rule for initializations already implemented as member initializers. For that purpose see check <a href="modernize-use-default-member-init.html">modernize-use-default-member-init</a>.</p> <h5 id="example-1">Example 1</h5> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> C { <span class="dt">int</span> n; <span class="dt">int</span> m; <span class="kw">public</span>: C() { n = <span class="dv">1</span>; <span class="co">// Literal in default constructor</span> <span class="kw">if</span> (dice()) <span class="kw">return</span>; m = <span class="dv">1</span>; } };</code></pre></div> <p>Here n can be initialized using a default member initializer, unlike m, as m’s initialization follows a control statement (if):</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> C { <span class="dt">int</span> n{<span class="dv">1</span>}; <span class="dt">int</span> m; <span class="kw">public</span>: C() { <span class="kw">if</span> (dice()) <span class="kw">return</span>; m = <span class="dv">1</span>; }</code></pre></div> <h5 id="example-2">Example 2</h5> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> C { <span class="dt">int</span> n; <span class="dt">int</span> m; <span class="kw">public</span>: C(<span class="dt">int</span> nn, <span class="dt">int</span> mm) { n = nn; <span class="co">// Neither default constructor nor literal</span> <span class="kw">if</span> (dice()) <span class="kw">return</span>; m = mm; } };</code></pre></div> <p>Here n can be initialized in the constructor initialization list, unlike m, as m’s initialization follows a control statement (if):</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">C(<span class="dt">int</span> nn, <span class="dt">int</span> mm) : n(nn) { <span class="kw">if</span> (dice()) <span class="kw">return</span>; m = mm; }</code></pre></div> <p>UseAssignment</p> <p>If this option is set to true (default is false), the check will initialize members with an assignment. In this case the fix of the first example looks like this:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> C { <span class="dt">int</span> n = <span class="dv">1</span>; <span class="dt">int</span> m; <span class="kw">public</span>: C() { <span class="kw">if</span> (dice()) <span class="kw">return</span>; m = <span class="dv">1</span>; } };</code></pre></div> <p>(Clang-Tidy original name: cppcoreguidelines-prefer-member-initializer)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-pro-type-const-cast + cppcoreguidelines + + true + Pro Type Const Cast + <p>This check flags all uses of const_cast in C++ code.</p> <p>Modifying a variable that was declared const is undefined behavior, even with const_cast.</p> <p>This rule is part of the “Type safety” profile of the C++ Core Guidelines, see <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-type-constcast" class="uri">https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-type-constcast</a>.</p> <p>(Clang-Tidy original name: cppcoreguidelines-pro-type-const-cast)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-pro-type-cstyle-cast + cppcoreguidelines + + true + Pro Type Cstyle Cast + <p>This check flags all use of C-style casts that perform a static_cast downcast, const_cast, or reinterpret_cast.</p> <p>Use of these casts can violate type safety and cause the program to access a variable that is actually of type X to be accessed as if it were of an unrelated type Z. Note that a C-style (T)expression cast means to perform the first of the following that is possible: a const_cast, a static_cast, a static_cast followed by a const_cast, a reinterpret_cast, or a reinterpret_cast followed by a const_cast. This rule bans (T)expression only when used to perform an unsafe cast.</p> <p>This rule is part of the “Type safety” profile of the C++ Core Guidelines, see <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-type-cstylecast" class="uri">https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-type-cstylecast</a>.</p> <p>(Clang-Tidy original name: cppcoreguidelines-pro-type-cstyle-cast)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-pro-type-member-init + cppcoreguidelines + + true + Pro Type Member Init + <p>The check flags user-defined constructor definitions that do not initialize all fields that would be left in an undefined state by default construction, e.g. builtins, pointers and record types without user-provided default constructors containing at least one such type. If these fields aren’t initialized, the constructor will leave some of the memory in an undefined state.</p> <p>For C++11 it suggests fixes to add in-class field initializers. For older versions it inserts the field initializers into the constructor initializer list. It will also initialize any direct base classes that need to be zeroed in the constructor initializer list.</p> <p>The check takes assignment of fields in the constructor body into account but generates false positives for fields initialized in methods invoked in the constructor body.</p> <p>The check also flags variables with automatic storage duration that have record types without a user-provided constructor and are not initialized. The suggested fix is to zero initialize the variable via {} for C++11 and beyond or = {} for older language versions.</p> <h5 id="options-74">Options</h5> <p>IgnoreArrays</p> <p>If set to true, the check will not warn about array members that are not zero-initialized during construction. For performance critical code, it may be important to not initialize fixed-size array members. Default is false.</p> <p>UseAssignment</p> <p>If set to true, the check will provide fix-its with literal initializers ( int i = 0; ) instead of curly braces ( int i{}; ).</p> <p>This rule is part of the “Type safety” profile of the C++ Core Guidelines, corresponding to rule Type.6. See <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-type-memberinit" class="uri">https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-type-memberinit</a>.</p> <p>(Clang-Tidy original name: cppcoreguidelines-pro-type-member-init)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-pro-type-reinterpret-cast + cppcoreguidelines + + true + Pro Type Reinterpret Cast + <p>This check flags all uses of reinterpret_cast in C++ code.</p> <p>Use of these casts can violate type safety and cause the program to access a variable that is actually of type X to be accessed as if it were of an unrelated type Z.</p> <p>This rule is part of the “Type safety” profile of the C++ Core Guidelines, see <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-type-reinterpretcast" class="uri">https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-type-reinterpretcast</a>.</p> <p>(Clang-Tidy original name: cppcoreguidelines-pro-type-reinterpret-cast)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-pro-type-static-cast-downcast + cppcoreguidelines + + true + Pro Type Static Cast Downcast + <p>This check flags all usages of static_cast, where a base class is casted to a derived class. In those cases, a fix-it is provided to convert the cast to a dynamic_cast.</p> <p>Use of these casts can violate type safety and cause the program to access a variable that is actually of type X to be accessed as if it were of an unrelated type Z.</p> <p>This rule is part of the “Type safety” profile of the C++ Core Guidelines, see <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-type-downcast" class="uri">https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-type-downcast</a>.</p> <p>(Clang-Tidy original name: cppcoreguidelines-pro-type-static-cast-downcast)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-pro-type-union-access + cppcoreguidelines + + true + Pro Type Union Access + <p>This check flags all access to members of unions. Passing unions as a whole is not flagged.</p> <p>Reading from a union member assumes that member was the last one written, and writing to a union member assumes another member with a nontrivial destructor had its destructor called. This is fragile because it cannot generally be enforced to be safe in the language and so relies on programmer discipline to get it right.</p> <p>This rule is part of the “Type safety” profile of the C++ Core Guidelines, see <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-type-unions" class="uri">https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-type-unions</a>.</p> <p>(Clang-Tidy original name: cppcoreguidelines-pro-type-union-access)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-pro-type-vararg + cppcoreguidelines + + true + Pro Type Vararg + <p>This check flags all calls to c-style vararg functions and all use of va_arg.</p> <p>To allow for SFINAE use of vararg functions, a call is not flagged if a literal 0 is passed as the only vararg argument.</p> <p>Passing to varargs assumes the correct type will be read. This is fragile because it cannot generally be enforced to be safe in the language and so relies on programmer discipline to get it right.</p> <p>This rule is part of the “Type safety” profile of the C++ Core Guidelines, see <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-type-varargs" class="uri">https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#Pro-type-varargs</a>.</p> <p>(Clang-Tidy original name: cppcoreguidelines-pro-type-vararg)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-slicing + cppcoreguidelines + + true + Slicing + <p>Flags slicing of member variables or vtable. Slicing happens when copying a derived object into a base object: the members of the derived object (both member variables and virtual member functions) will be discarded. This can be misleading especially for member function slicing, for example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> B { <span class="dt">int</span> a; <span class="kw">virtual</span> <span class="dt">int</span> f(); }; <span class="kw">struct</span> D : B { <span class="dt">int</span> b; <span class="dt">int</span> f() <span class="kw">override</span>; }; <span class="dt">void</span> use(B b) { <span class="co">// Missing reference, intended?</span> b.f(); <span class="co">// Calls B::f.</span> } D d; use(d); <span class="co">// Slice.</span></code></pre></div> <p>See the relevant C++ Core Guidelines sections for details: <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#es63-dont-slice" class="uri">https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#es63-dont-slice</a> <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#c145-access-polymorphic-objects-through-pointers-and-references" class="uri">https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#c145-access-polymorphic-objects-through-pointers-and-references</a></p> <p>(Clang-Tidy original name: cppcoreguidelines-slicing)</p> + + + + Major + + + + + + + true + false + cppcoreguidelines-special-member-functions + cppcoreguidelines + + true + Special Member Functions + <p>The check finds classes where some but not all of the special member functions are defined.</p> <p>By default the compiler defines a copy constructor, copy assignment operator, move constructor, move assignment operator and destructor. The default can be suppressed by explicit user-definitions. The relationship between which functions will be suppressed by definitions of other functions is complicated and it is advised that all five are defaulted or explicitly defined.</p> <p>Note that defining a function with = delete is considered to be a definition.</p> <p>This rule is part of the “Constructors, assignments, and destructors” profile of the C++ Core Guidelines, corresponding to rule C.21. See</p> <p><a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#c21-if-you-define-or-delete-any-default-operation-define-or-delete-them-all" class="uri">https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\#c21-if-you-define-or-delete-any-default-operation-define-or-delete-them-all</a>.</p> <h5 id="options-54">Options</h5> <p>AllowSoleDefaultDtor</p> <p>When set to true (default is false), this check doesn’t flag classes with a sole, explicitly defaulted destructor. An example for such a class is:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> A { <span class="kw">virtual</span> ~A() = <span class="kw">default</span>; };</code></pre></div> <p>AllowMissingMoveFunctions</p> <p>When set to true (default is false), this check doesn’t flag classes which define no move operations at all. It still flags classes which define only one of either move constructor or move assignment operator. With this option enabled, the following class won’t be flagged:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> A { A(<span class="dt">const</span> A&amp;); A&amp; <span class="kw">operator</span>=(<span class="dt">const</span> A&amp;); ~A(); };</code></pre></div> <p>AllowMissingMoveFunctionsWhenCopyIsDeleted</p> <p>When set to true (default is false), this check doesn’t flag classes which define deleted copy operations but don’t define move operations. This flags is related to Google C++ Style Guide <a href="https://google.github.io/styleguide/cppguide.html\#Copyable_Movable_Types" class="uri">https://google.github.io/styleguide/cppguide.html\#Copyable_Movable_Types</a>. With this option enabled, the following class won’t be flagged:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> A { A(<span class="dt">const</span> A&amp;) = <span class="kw">delete</span>; A&amp; <span class="kw">operator</span>=(<span class="dt">const</span> A&amp;) = <span class="kw">delete</span>; ~A(); };</code></pre></div> <p>(Clang-Tidy original name: cppcoreguidelines-special-member-functions)</p> + + + + Major + + + + + + + true + false + cert-con36-c + cert + + true + Con36 C + <p>The cert-con36-c check is an alias, please see <a href="bugprone-spuriously-wake-up-functions.html">bugprone-spuriously-wake-up-functions</a> for more information.</p> <p>(Clang-Tidy original name: cert-con36-c)</p> + + + + Major + + + + + + + true + false + cert-con54-cpp + cert + + true + Con54 Cpp + <p>The cert-con54-cpp check is an alias, please see <a href="bugprone-spuriously-wake-up-functions.html">bugprone-spuriously-wake-up-functions</a> for more information.</p> <p>(Clang-Tidy original name: cert-con54-cpp)</p> + + + + Major + + + + + + + true + false + cert-dcl03-c + cert + + true + Dcl03 C + <p>The cert-dcl03-c check is an alias, please see <a href="misc-static-assert.html">misc-static-assert</a> for more information.</p> <p>(Clang-Tidy original name: cert-dcl03-c)</p> + + + + Major + + + + + + + true + false + cert-dcl16-c + cert + + true + Dcl16 C + <p>The cert-dcl16-c check is an alias, please see <a href="readability-uppercase-literal-suffix.html">readability-uppercase-literal-suffix</a> for more information.</p> <p>(Clang-Tidy original name: cert-dcl16-c)</p> + + + + Major + + + + + + + true + false + cert-dcl21-cpp + cert + + true + Dcl21 Cpp + <p>This check flags postfix operator++ and operator-- declarations if the return type is not a const object. This also warns if the return type is a reference type.</p> <p>The object returned by a postfix increment or decrement operator is supposed to be a snapshot of the object’s value prior to modification. With such an implementation, any modifications made to the resulting object from calling operator++(int) would be modifying a temporary object. Thus, such an implementation of a postfix increment or decrement operator should instead return a const object, prohibiting accidental mutation of a temporary object. Similarly, it is unexpected for the postfix operator to return a reference to its previous state, and any subsequent modifications would be operating on a stale object.</p> <p>This check corresponds to the CERT C++ Coding Standard recommendation DCL21-CPP. Overloaded postfix increment and decrement operators should return a const object. However, all of the CERT recommendations have been removed from public view, and so their justification for the behavior of this check requires an account on their wiki to view.</p> <p>(Clang-Tidy original name: cert-dcl21-cpp)</p> + + + + Major + + + + + + + true + false + cert-dcl37-c + cert + + true + Dcl37 C + <p>The cert-dcl37-c check is an alias, please see <a href="bugprone-reserved-identifier.html">bugprone-reserved-identifier</a> for more information.</p> <p>(Clang-Tidy original name: cert-dcl37-c)</p> + + + + Major + + + + + + + true + false + cert-dcl50-cpp + cert + + true + Dcl50 Cpp + <p>This check flags all function definitions (but not declarations) of C-style variadic functions.</p> <p>This check corresponds to the CERT C++ Coding Standard rule <a href="https://www.securecoding.cert.org/confluence/display/cplusplus/DCL50-CPP.+Do+not+define+a+C-style+variadic+function">DCL50-CPP. Do not define a C-style variadic function</a>.</p> <p>(Clang-Tidy original name: cert-dcl50-cpp)</p> + + + + Major + + + + + + + true + false + cert-dcl51-cpp + cert + + true + Dcl51 Cpp + <p>The cert-dcl51-cpp check is an alias, please see <a href="bugprone-reserved-identifier.html">bugprone-reserved-identifier</a> for more information.</p> <p>(Clang-Tidy original name: cert-dcl51-cpp)</p> + + + + Major + + + + + + + true + false + cert-dcl54-cpp + cert + + true + Dcl54 Cpp + <p>The cert-dcl54-cpp check is an alias, please see <a href="misc-new-delete-overloads.html">misc-new-delete-overloads</a> for more information.</p> <p>(Clang-Tidy original name: cert-dcl54-cpp)</p> + + + + Major + + + + + + + true + false + cert-dcl58-cpp + cert + + true + Dcl58 Cpp + <p>Modification of the std or posix namespace can result in undefined behavior. This check warns for such modifications.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">namespace</span> std { <span class="dt">int</span> x; <span class="co">// May cause undefined behavior.</span> }</code></pre></div> <p>This check corresponds to the CERT C++ Coding Standard rule <a href="https://www.securecoding.cert.org/confluence/display/cplusplus/DCL58-CPP.+Do+not+modify+the+standard+namespaces">DCL58-CPP. Do not modify the standard namespaces</a>.</p> <p>(Clang-Tidy original name: cert-dcl58-cpp)</p> + + + + Major + + + + + + + true + false + cert-dcl59-cpp + cert + + true + Dcl59 Cpp + <p>The cert-dcl59-cpp check is an alias, please see <a href="google-build-namespaces.html">google-build-namespaces</a> for more information.</p> <p>(Clang-Tidy original name: cert-dcl59-cpp)</p> + + + + Major + + + + + + + true + false + cert-env33-c + cert + + true + Env33 C + <p>This check flags calls to system(), popen(), and _popen(), which execute a command processor. It does not flag calls to system() with a null pointer argument, as such a call checks for the presence of a command processor but does not actually attempt to execute a command.</p> <p>This check corresponds to the CERT C Coding Standard rule <a href="https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=2130132">ENV33-C. Do not call system()</a>.</p> <p>(Clang-Tidy original name: cert-env33-c)</p> + + + + Major + + + + + + + true + false + cert-err09-cpp + cert + + true + Err09 Cpp + <p>The cert-err09-cpp check is an alias, please see <a href="misc-throw-by-value-catch-by-reference.html">misc-throw-by-value-catch-by-reference</a> for more information.</p> <p>This check corresponds to the CERT C++ Coding Standard recommendation ERR09-CPP. Throw anonymous temporaries. However, all of the CERT recommendations have been removed from public view, and so their justification for the behavior of this check requires an account on their wiki to view.</p> <p>(Clang-Tidy original name: cert-err09-cpp)</p> + + + + Major + + + + + + + true + false + cert-err34-c + cert + + true + Err34 C + <p>This check flags calls to string-to-number conversion functions that do not verify the validity of the conversion, such as atoi() or scanf(). It does not flag calls to strtol(), or other, related conversion functions that do perform better error checking.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#include &lt;stdlib.h&gt;</span> <span class="dt">void</span> func(<span class="dt">const</span> <span class="dt">char</span> *buff) { <span class="dt">int</span> si; <span class="kw">if</span> (buff) { si = atoi(buff); <span class="co">/* &#39;atoi&#39; used to convert a string to an integer, but function will</span> <span class="co"> not report conversion errors; consider using &#39;strtol&#39; instead. */</span> } <span class="kw">else</span> { <span class="co">/* Handle error */</span> } }</code></pre></div> <p>This check corresponds to the CERT C Coding Standard rule <a href="https://www.securecoding.cert.org/confluence/display/c/ERR34-C.+Detect+errors+when+converting+a+string+to+a+number">ERR34-C. Detect errors when converting a string to a number</a>.</p> <p>(Clang-Tidy original name: cert-err34-c)</p> + + + + Major + + + + + + + true + false + cert-err52-cpp + cert + + true + Err52 Cpp + <p>This check flags all call expressions involving setjmp() and longjmp().</p> <p>This check corresponds to the CERT C++ Coding Standard rule <a href="https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=1834">ERR52-CPP. Do not use setjmp() or longjmp()</a>.</p> <p>(Clang-Tidy original name: cert-err52-cpp)</p> + + + + Major + + + + + + + true + false + cert-err58-cpp + cert + + true + Err58 Cpp + <p>This check flags all static or thread_local variable declarations where the initializer for the object may throw an exception.</p> <p>This check corresponds to the CERT C++ Coding Standard rule <a href="https://www.securecoding.cert.org/confluence/display/cplusplus/ERR58-CPP.+Handle+all+exceptions+thrown+before+main%28%29+begins+executing">ERR58-CPP. Handle all exceptions thrown before main() begins executing</a>.</p> <p>(Clang-Tidy original name: cert-err58-cpp)</p> + + + + Major + + + + + + + true + false + cert-err60-cpp + cert + + true + Err60 Cpp + <p>This check flags all throw expressions where the exception object is not nothrow copy constructible.</p> <p>This check corresponds to the CERT C++ Coding Standard rule <a href="https://www.securecoding.cert.org/confluence/display/cplusplus/ERR60-CPP.+Exception+objects+must+be+nothrow+copy+constructible">ERR60-CPP. Exception objects must be nothrow copy constructible</a>.</p> <p>(Clang-Tidy original name: cert-err60-cpp)</p> + + + + Major + + + + + + + true + false + cert-err61-cpp + cert + + true + Err61 Cpp + <p>The cert-err61-cpp check is an alias, please see <a href="misc-throw-by-value-catch-by-reference.html">misc-throw-by-value-catch-by-reference</a> for more information.</p> <p>(Clang-Tidy original name: cert-err61-cpp)</p> + + + + Major + + + + + + + true + false + cert-fio38-c + cert + + true + Fio38 C + <p>The cert-fio38-c check is an alias, please see <a href="misc-non-copyable-objects.html">misc-non-copyable-objects</a> for more information.</p> <p>(Clang-Tidy original name: cert-fio38-c)</p> + + + + Major + + + + + + + true + false + cert-flp30-c + cert + + true + Flp30 C + <p>This check flags for loops where the induction expression has a floating-point type.</p> <p>This check corresponds to the CERT C Coding Standard rule <a href="https://www.securecoding.cert.org/confluence/display/c/FLP30-C.+Do+not+use+floating-point+variables+as+loop+counters">FLP30-C. Do not use floating-point variables as loop counters</a>.</p> <p>(Clang-Tidy original name: cert-flp30-c)</p> + + + + Major + + + + + + + true + false + cert-mem57-cpp + cert + + true + Mem57 Cpp + <p>This check flags uses of default operator new where the type has extended alignment (an alignment greater than the fundamental alignment). (The default operator new is guaranteed to provide the correct alignment if the requested alignment is less or equal to the fundamental alignment). Only cases are detected (by design) where the operator new is not user-defined and is not a placement new (the reason is that in these cases we assume that the user provided the correct memory allocation).</p> <p>This check corresponds to the CERT C++ Coding Standard rule <a href="https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM57-CPP.+Avoid+using+default+operator+new+for+over-aligned+types">MEM57-CPP. Avoid using default operator new for over-aligned types</a>.</p> <p>(Clang-Tidy original name: cert-mem57-cpp)</p> + + + + Major + + + + + + + true + false + cert-msc30-c + cert + + true + Msc30 C + <p>The cert-msc30-c check is an alias, please see <a href="cert-msc50-cpp.html">cert-msc50-cpp</a> for more information.</p> <p>(Clang-Tidy original name: cert-msc30-c)</p> + + + + Major + + + + + + + true + false + cert-msc32-c + cert + + true + Msc32 C + <p>The cert-msc32-c check is an alias, please see <a href="cert-msc51-cpp.html">cert-msc51-cpp</a> for more information.</p> <p>(Clang-Tidy original name: cert-msc32-c)</p> + + + + Major + + + + + + + true + false + cert-msc50-cpp + cert + + true + Msc50 Cpp + <p>Pseudorandom number generators use mathematical algorithms to produce a sequence of numbers with good statistical properties, but the numbers produced are not genuinely random. The std::rand() function takes a seed (number), runs a mathematical operation on it and returns the result. By manipulating the seed the result can be predictable. This check warns for the usage of std::rand().</p> <p>(Clang-Tidy original name: cert-msc50-cpp)</p> + + + + Major + + + + + + + true + false + cert-msc51-cpp + cert + + true + Msc51 Cpp + <p>This check flags all pseudo-random number engines, engine adaptor instantiations and srand() when initialized or seeded with default argument, constant expression or any user-configurable type. Pseudo-random number engines seeded with a predictable value may cause vulnerabilities e.g. in security protocols. This is a CERT security rule, see <a href="https://wiki.sei.cmu.edu/confluence/display/cplusplus/MSC51-CPP.+Ensure+your+random+number+generator+is+properly+seeded">MSC51-CPP. Ensure your random number generator is properly seeded</a> and <a href="https://wiki.sei.cmu.edu/confluence/display/c/MSC32-C.+Properly+seed+pseudorandom+number+generators">MSC32-C. Properly seed pseudorandom number generators</a>.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo() { std::mt19937 engine1; <span class="co">// Diagnose, always generate the same sequence</span> std::mt19937 engine2(<span class="dv">1</span>); <span class="co">// Diagnose</span> engine1.seed(); <span class="co">// Diagnose</span> engine2.seed(<span class="dv">1</span>); <span class="co">// Diagnose</span> std::time_t t; engine1.seed(std::time(&amp;t)); <span class="co">// Diagnose, system time might be controlled by user</span> <span class="dt">int</span> x = atoi(argv[<span class="dv">1</span>]); std::mt19937 engine3(x); <span class="co">// Will not warn</span> }</code></pre></div> <h5 id="options-71">Options</h5> <p>DisallowedSeedTypes</p> <p>A comma-separated list of the type names which are disallowed. Default values are time_t, std::time_t.</p> <p>(Clang-Tidy original name: cert-msc51-cpp)</p> + + + + Major + + + + + + + true + false + cert-oop11-cpp + cert + + true + Oop11 Cpp + <p>The cert-oop11-cpp check is an alias, please see <a href="performance-move-constructor-init.html">performance-move-constructor-init</a> for more information.</p> <p>This check corresponds to the CERT C++ Coding Standard recommendation OOP11-CPP. Do not copy-initialize members or base classes from a move constructor. However, all of the CERT recommendations have been removed from public view, and so their justification for the behavior of this check requires an account on their wiki to view.</p> <p>(Clang-Tidy original name: cert-oop11-cpp)</p> + + + + Major + + + + + + + true + false + cert-oop54-cpp + cert + + true + Oop54 Cpp + <p>The cert-oop54-cpp check is an alias, please see <a href="bugprone-unhandled-self-assignment.html">bugprone-unhandled-self-assignment</a> for more information.</p> <p>(Clang-Tidy original name: cert-oop54-cpp)</p> + + + + Major + + + + + + + true + false + cert-oop57-cpp + cert + + true + Oop57 Cpp + <p>Flags use of the C standard library functions memset, memcpy and memcmp and similar derivatives on non-trivial types.</p> <h5 id="options-58">Options</h5> <p>MemSetNames</p> <p>Specify extra functions to flag that act similarily to memset. Specify names in a semicolon delimited list. Default is an empty string. The check will detect the following functions: memset, std::memset.</p> <p>MemCpyNames</p> <p>Specify extra functions to flag that act similarily to memcpy. Specify names in a semicolon delimited list. Default is an empty string. The check will detect the following functions: std::memcpy, memcpy, std::memmove, memmove, std::strcpy, strcpy, memccpy, stpncpy, strncpy.</p> <p>MemCmpNames</p> <p>Specify extra functions to flag that act similarily to memcmp. Specify names in a semicolon delimited list. Default is an empty string. The check will detect the following functions: std::memcmp, memcmp, std::strcmp, strcmp, strncmp.</p> <p>This check corresponds to the CERT C++ Coding Standard rule <a href="https://wiki.sei.cmu.edu/confluence/display/cplusplus/OOP57-CPP.+Prefer+special+member+functions+and+overloaded+operators+to+C+Standard+Library+functions">OOP57-CPP. Prefer special member functions and overloaded operators to C Standard Library functions</a>.</p> <p>(Clang-Tidy original name: cert-oop57-cpp)</p> + + + + Major + + + + + + + true + false + cert-oop58-cpp + cert + + true + Oop58 Cpp + <p>Finds assignments to the copied object and its direct or indirect members in copy constructors and copy assignment operators.</p> <p>This check corresponds to the CERT C Coding Standard rule <a href="https://wiki.sei.cmu.edu/confluence/display/cplusplus/OOP58-CPP.+Copy+operations+must+not+mutate+the+source+object">OOP58-CPP. Copy operations must not mutate the source object</a>.</p> <p>(Clang-Tidy original name: cert-oop58-cpp)</p> + + + + Major + + + + + + + true + false + cert-pos44-c + cert + + true + Pos44 C + <p>The cert-pos44-c check is an alias, please see <a href="bugprone-bad-signal-to-kill-thread.html">bugprone-bad-signal-to-kill-thread</a> for more information.</p> <p>(Clang-Tidy original name: cert-pos44-c)</p> + + + + Major + + + + + + + true + false + cert-sig30-c + cert + + true + Sig30 C + <p>The cert-sig30-c check is an alias, please see <a href="bugprone-signal-handler.html">bugprone-signal-handler</a> for more information.</p> <p>(Clang-Tidy original name: cert-sig30-c)</p> + + + + Major + + + + + + + true + false + cert-str34-c + cert + + true + Str34 C + <p>The cert-str34-c check is an alias, please see <a href="bugprone-signed-char-misuse.html">bugprone-signed-char-misuse</a> for more information.</p> <p>(Clang-Tidy original name: cert-str34-c)</p> + + + + Major + + + + + + + false + false + darwin-avoid-spinlock + darwin + + true + Avoid Spinlock + <p>Finds usages of OSSpinlock, which is deprecated due to potential livelock problems.</p> <p>This check will detect following function invocations:</p> <ul> <li>OSSpinlockLock</li> <li>OSSpinlockTry</li> <li>OSSpinlockUnlock</li> </ul> <p>The corresponding information about the problem of OSSpinlock: <a href="https://blog.postmates.com/why-spinlocks-are-bad-on-ios-b69fc5221058" class="uri">https://blog.postmates.com/why-spinlocks-are-bad-on-ios-b69fc5221058</a></p> <p>(Clang-Tidy original name: darwin-avoid-spinlock)</p> + + + + Major + + + + + + + false + false + darwin-dispatch-once-nonstatic + darwin + + true + Dispatch Once Nonstatic + <p>Finds declarations of dispatch_once_t variables without static or global storage. The behavior of using dispatch_once_t predicates with automatic or dynamic storage is undefined by libdispatch, and should be avoided.</p> <p>It is a common pattern to have functions initialize internal static or global data once when the function runs, but programmers have been known to miss the static on the dispatch_once_t predicate, leading to an uninitialized flag value at the mercy of the stack.</p> <p>Programmers have also been known to make dispatch_once_t variables be members of structs or classes, with the intent to lazily perform some expensive struct or class member initialization only once; however, this violates the libdispatch requirements.</p> <p>See the discussion section of <a href="https://developer.apple.com/documentation/dispatch/1447169-dispatch_once">Apple’s dispatch_once documentation</a> for more information.</p> <p>(Clang-Tidy original name: darwin-dispatch-once-nonstatic)</p> + + + + Major + + + + + + + false + false + fuchsia-default-arguments-calls + fuchsia + + true + Default Arguments Calls + <p>Warns if a function or method is called with default arguments.</p> <p>For example, given the declaration:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> foo(<span class="dt">int</span> value = <span class="dv">5</span>) { <span class="kw">return</span> value; }</code></pre></div> <p>A function call expression that uses a default argument will be diagnosed. Calling it without defaults will not cause a warning:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">foo(); <span class="co">// warning</span> foo(<span class="dv">0</span>); <span class="co">// no warning</span></code></pre></div> <p>See the features disallowed in Fuchsia at <a href="https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md" class="uri">https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md</a></p> <p>(Clang-Tidy original name: fuchsia-default-arguments-calls)</p> + + + + Major + + + + + + + false + false + fuchsia-default-arguments-declarations + fuchsia + + true + Default Arguments Declarations + <p>Warns if a function or method is declared with default parameters.</p> <p>For example, the declaration:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> foo(<span class="dt">int</span> value = <span class="dv">5</span>) { <span class="kw">return</span> value; }</code></pre></div> <p>will cause a warning.</p> <p>See the features disallowed in Fuchsia at <a href="https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md" class="uri">https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md</a></p> <p>(Clang-Tidy original name: fuchsia-default-arguments-declarations)</p> + + + + Major + + + + + + + false + false + fuchsia-header-anon-namespaces + fuchsia + + true + Header Anon Namespaces + <p>The fuchsia-header-anon-namespaces check is an alias, please see <a href="google-build-namespaces.html">google-build-namespace</a> for more information.</p> <p>(Clang-Tidy original name: fuchsia-header-anon-namespaces)</p> + + + + Major + + + + + + + false + false + fuchsia-multiple-inheritance + fuchsia + + true + Multiple Inheritance + <p>Warns if a class inherits from multiple classes that are not pure virtual.</p> <p>For example, declaring a class that inherits from multiple concrete classes is disallowed:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Base_A { <span class="kw">public</span>: <span class="kw">virtual</span> <span class="dt">int</span> foo() { <span class="kw">return</span> <span class="dv">0</span>; } }; <span class="kw">class</span> Base_B { <span class="kw">public</span>: <span class="kw">virtual</span> <span class="dt">int</span> bar() { <span class="kw">return</span> <span class="dv">0</span>; } }; <span class="co">// Warning</span> <span class="kw">class</span> Bad_Child1 : <span class="kw">public</span> Base_A, Base_B {};</code></pre></div> <p>A class that inherits from a pure virtual is allowed:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Interface_A { <span class="kw">public</span>: <span class="kw">virtual</span> <span class="dt">int</span> foo() = <span class="dv">0</span>; }; <span class="kw">class</span> Interface_B { <span class="kw">public</span>: <span class="kw">virtual</span> <span class="dt">int</span> bar() = <span class="dv">0</span>; }; <span class="co">// No warning</span> <span class="kw">class</span> Good_Child1 : <span class="kw">public</span> Interface_A, Interface_B { <span class="kw">virtual</span> <span class="dt">int</span> foo() <span class="kw">override</span> { <span class="kw">return</span> <span class="dv">0</span>; } <span class="kw">virtual</span> <span class="dt">int</span> bar() <span class="kw">override</span> { <span class="kw">return</span> <span class="dv">0</span>; } };</code></pre></div> <p>See the features disallowed in Fuchsia at <a href="https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md" class="uri">https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md</a></p> <p>(Clang-Tidy original name: fuchsia-multiple-inheritance)</p> + + + + Major + + + + + + + false + false + fuchsia-overloaded-operator + fuchsia + + true + Overloaded Operator + <p>Warns if an operator is overloaded, except for the assignment (copy and move) operators.</p> <p>For example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> <span class="kw">operator</span>+(<span class="dt">int</span>); <span class="co">// Warning</span> B &amp;<span class="kw">operator</span>=(<span class="dt">const</span> B &amp;Other); <span class="co">// No warning</span> B &amp;<span class="kw">operator</span>=(B &amp;&amp;Other) <span class="co">// No warning</span></code></pre></div> <p>See the features disallowed in Fuchsia at <a href="https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md" class="uri">https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md</a></p> <p>(Clang-Tidy original name: fuchsia-overloaded-operator)</p> + + + + Major + + + + + + + false + false + fuchsia-statically-constructed-objects + fuchsia + + true + Statically Constructed Objects + <p>Warns if global, non-trivial objects with static storage are constructed, unless the object is statically initialized with a constexpr constructor or has no explicit constructor.</p> <p>For example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> A {}; <span class="kw">class</span> B { <span class="kw">public</span>: B(<span class="dt">int</span> Val) : Val(Val) {} <span class="kw">private</span>: <span class="dt">int</span> Val; }; <span class="kw">class</span> C { <span class="kw">public</span>: C(<span class="dt">int</span> Val) : Val(Val) {} <span class="kw">constexpr</span> C() : Val(<span class="dv">0</span>) {} <span class="kw">private</span>: <span class="dt">int</span> Val; }; <span class="dt">static</span> A a; <span class="co">// No warning, as there is no explicit constructor</span> <span class="dt">static</span> C c(<span class="dv">0</span>); <span class="co">// No warning, as constructor is constexpr</span> <span class="dt">static</span> B b(<span class="dv">0</span>); <span class="co">// Warning, as constructor is not constexpr</span> <span class="dt">static</span> C c2(<span class="dv">0</span>, <span class="dv">1</span>); <span class="co">// Warning, as constructor is not constexpr</span> <span class="dt">static</span> <span class="dt">int</span> i; <span class="co">// No warning, as it is trivial</span> <span class="dt">extern</span> <span class="dt">int</span> get_i(); <span class="dt">static</span> C(get_i()) <span class="co">// Warning, as the constructor is dynamically initialized</span></code></pre></div> <p>See the features disallowed in Fuchsia at <a href="https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md" class="uri">https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md</a></p> <p>(Clang-Tidy original name: fuchsia-statically-constructed-objects)</p> + + + + Major + + + + + + + false + false + fuchsia-trailing-return + fuchsia + + true + Trailing Return + <p>Functions that have trailing returns are disallowed, except for those using decltype specifiers and lambda with otherwise unutterable return types.</p> <p>For example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// No warning</span> <span class="dt">int</span> add_one(<span class="dt">const</span> <span class="dt">int</span> arg) { <span class="kw">return</span> arg; } <span class="co">// Warning</span> <span class="kw">auto</span> get_add_one() -&gt; <span class="dt">int</span> (*)(<span class="dt">const</span> <span class="dt">int</span>) { <span class="kw">return</span> add_one; }</code></pre></div> <p>Exceptions are made for lambdas and decltype specifiers:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// No warning</span> <span class="kw">auto</span> lambda = [](<span class="dt">double</span> x, <span class="dt">double</span> y) -&gt; <span class="dt">double</span> {<span class="kw">return</span> x + y;}; <span class="co">// No warning</span> <span class="kw">template</span> &lt;<span class="kw">typename</span> T1, <span class="kw">typename</span> T2&gt; <span class="kw">auto</span> fn(<span class="dt">const</span> T1 &amp;lhs, <span class="dt">const</span> T2 &amp;rhs) -&gt; <span class="kw">decltype</span>(lhs + rhs) { <span class="kw">return</span> lhs + rhs; }</code></pre></div> <p>See the features disallowed in Fuchsia at <a href="https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md" class="uri">https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md</a></p> <p>(Clang-Tidy original name: fuchsia-trailing-return)</p> + + + + Major + + + + + + + false + false + fuchsia-virtual-inheritance + fuchsia + + true + Virtual Inheritance + <p>Warns if classes are defined with virtual inheritance.</p> <p>For example, classes should not be defined with virtual inheritance:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> B : <span class="kw">public</span> <span class="kw">virtual</span> A {}; <span class="co">// warning</span></code></pre></div> <p>See the features disallowed in Fuchsia at <a href="https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md" class="uri">https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md</a></p> <p>(Clang-Tidy original name: fuchsia-virtual-inheritance)</p> + + + + Major + + + + + + + false + false + google-build-explicit-make-pair + google + + true + Build Explicit Make Pair + <p>Check that make_pair’s template arguments are deduced.</p> <p>G++ 4.6 in C++11 mode fails badly if make_pair’s template arguments are specified explicitly, and such use isn’t intended in any case.</p> <p>Corresponding cpplint.py check name: build/explicit_make_pair.</p> <p>(Clang-Tidy original name: google-build-explicit-make-pair)</p> + + + + Major + + + + + + + false + false + google-build-namespaces + google + + true + Build Namespaces + <p>cert-dcl59-cpp redirects here as an alias for this check. fuchsia-header-anon-namespaces redirects here as an alias for this check.</p> <p>Finds anonymous namespaces in headers.</p> <p><a href="https://google.github.io/styleguide/cppguide.html\#Namespaces" class="uri">https://google.github.io/styleguide/cppguide.html\#Namespaces</a></p> <p>Corresponding cpplint.py check name: build/namespaces.</p> <h5 id="options-63">Options</h5> <p>HeaderFileExtensions</p> <p>A comma-separated list of filename extensions of header files (the filename extensions should not include “.” prefix). Default is “h,hh,hpp,hxx”. For header files without an extension, use an empty string (if there are no other desired extensions) or leave an empty element in the list. e.g., “h,hh,hpp,hxx,” (note the trailing comma).</p> <p>(Clang-Tidy original name: google-build-namespaces)</p> + + + + Major + + + + + + + false + false + google-build-using-namespace + google + + true + Build Using Namespace + <p>Finds using namespace directives.</p> <p>The check implements the following rule of the <a href="https://google.github.io/styleguide/cppguide.html#Namespaces">Google C++ Style Guide</a>:</p> <p>You may not use a using-directive to make all names from a namespace available.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Forbidden -- This pollutes the namespace.</span> <span class="kw">using</span> <span class="kw">namespace</span> foo;</code></pre></div> <p>Corresponding cpplint.py check name: build/namespaces.</p> <p>(Clang-Tidy original name: google-build-using-namespace)</p> + + + + Major + + + + + + + false + false + google-default-arguments + google + + true + Default Arguments + <p>Checks that default arguments are not given for virtual methods.</p> <p>See <a href="https://google.github.io/styleguide/cppguide.html\#Default_Arguments" class="uri">https://google.github.io/styleguide/cppguide.html\#Default_Arguments</a></p> <p>(Clang-Tidy original name: google-default-arguments)</p> + + + + Major + + + + + + + false + false + google-explicit-constructor + google + + true + Explicit Constructor + <p>Checks that constructors callable with a single argument and conversion operators are marked explicit to avoid the risk of unintentional implicit conversions.</p> <p>Consider this example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> S { <span class="dt">int</span> x; <span class="kw">operator</span> <span class="dt">bool</span>() <span class="dt">const</span> { <span class="kw">return</span> <span class="kw">true</span>; } }; <span class="dt">bool</span> f() { S a{<span class="dv">1</span>}; S b{<span class="dv">2</span>}; <span class="kw">return</span> a == b; }</code></pre></div> <p>The function will return true, since the objects are implicitly converted to bool before comparison, which is unlikely to be the intent.</p> <p>The check will suggest inserting explicit before the constructor or conversion operator declaration. However, copy and move constructors should not be explicit, as well as constructors taking a single initializer_list argument.</p> <p>This code:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> S { S(<span class="dt">int</span> a); <span class="kw">explicit</span> S(<span class="dt">const</span> S&amp;); <span class="kw">operator</span> <span class="dt">bool</span>() <span class="dt">const</span>; ...</code></pre></div> <p>will become</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> S { <span class="kw">explicit</span> S(<span class="dt">int</span> a); S(<span class="dt">const</span> S&amp;); <span class="kw">explicit</span> <span class="kw">operator</span> <span class="dt">bool</span>() <span class="dt">const</span>; ...</code></pre></div> <p>See <a href="https://google.github.io/styleguide/cppguide.html\#Explicit_Constructors" class="uri">https://google.github.io/styleguide/cppguide.html\#Explicit_Constructors</a></p> <p>(Clang-Tidy original name: google-explicit-constructor)</p> + + + + Major + + + + + + + false + false + google-global-names-in-headers + google + + true + Global Names In Headers + <p>Flag global namespace pollution in header files. Right now it only triggers on using declarations and directives.</p> <p>The relevant style guide section is <a href="https://google.github.io/styleguide/cppguide.html\#Namespaces" class="uri">https://google.github.io/styleguide/cppguide.html\#Namespaces</a>.</p> <h5 id="options-64">Options</h5> <p>HeaderFileExtensions</p> <p>A comma-separated list of filename extensions of header files (the filename extensions should not contain “.” prefix). Default is “h”. For header files without an extension, use an empty string (if there are no other desired extensions) or leave an empty element in the list. e.g., “h,hh,hpp,hxx,” (note the trailing comma).</p> <p>(Clang-Tidy original name: google-global-names-in-headers)</p> + + + + Major + + + + + + + false + false + google-objc-avoid-nsobject-new + google + + true + Objc Avoid Nsobject New + <p>Finds calls to +new or overrides of it, which are prohibited by the Google Objective-C style guide.</p> <p>The Google Objective-C style guide forbids calling +new or overriding it in class implementations, preferring +alloc and -init methods to instantiate objects.</p> <p>An example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">NSDate *now = [NSDate <span class="kw">new</span>]; Foo *bar = [Foo <span class="kw">new</span>];</code></pre></div> <p>Instead, code should use +alloc/-init or class factory methods.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">NSDate *now = [NSDate date]; Foo *bar = [[<span class="kw">Foo</span> <span class="kw">alloc</span>] <span class="kw">init</span>];</code></pre></div> <p>This check corresponds to the Google Objective-C Style Guide rule <a href="https://google.github.io/styleguide/objcguide.html#do-not-use-new">Do Not Use +new</a>.</p> <p>(Clang-Tidy original name: google-objc-avoid-nsobject-new)</p> + + + + Major + + + + + + + false + false + google-objc-avoid-throwing-exception + google + + true + Objc Avoid Throwing Exception + <p>Finds uses of throwing exceptions usages in Objective-C files.</p> <p>For the same reason as the Google C++ style guide, we prefer not throwing exceptions from Objective-C code.</p> <p>The corresponding C++ style guide rule: <a href="https://google.github.io/styleguide/cppguide.html\#Exceptions" class="uri">https://google.github.io/styleguide/cppguide.html\#Exceptions</a></p> <p>Instead, prefer passing in NSError ** and return BOOL to indicate success or failure.</p> <p>A counterexample:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">- (<span class="dt">void</span>)readFile { <span class="kw">if</span> ([self isError]) { <span class="er">@</span>throw [NSException exceptionWithName:...]; } }</code></pre></div> <p>Instead, returning an error via NSError ** is preferred:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">- (BOOL)readFileWithError:(NSError **)error { <span class="kw">if</span> ([self isError]) { *error = [NSError errorWithDomain:...]; <span class="kw">return</span> NO; } <span class="kw">return</span> YES; }</code></pre></div> <p>The corresponding style guide rule: <a href="https://google.github.io/styleguide/objcguide.html\#avoid-throwing-exceptions" class="uri">https://google.github.io/styleguide/objcguide.html\#avoid-throwing-exceptions</a></p> <p>(Clang-Tidy original name: google-objc-avoid-throwing-exception)</p> + + + + Major + + + + + + + false + false + google-objc-function-naming + google + + true + Objc Function Naming + <p>Finds function declarations in Objective-C files that do not follow the pattern described in the Google Objective-C Style Guide.</p> <p>The corresponding style guide rule can be found here: <a href="https://google.github.io/styleguide/objcguide.html\#function-names" class="uri">https://google.github.io/styleguide/objcguide.html\#function-names</a></p> <p>All function names should be in Pascal case. Functions whose storage class is not static should have an appropriate prefix.</p> <p>The following code sample does not follow this pattern:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">static</span> <span class="dt">bool</span> is_positive(<span class="dt">int</span> i) { <span class="kw">return</span> i &gt; <span class="dv">0</span>; } <span class="dt">bool</span> IsNegative(<span class="dt">int</span> i) { <span class="kw">return</span> i &lt; <span class="dv">0</span>; }</code></pre></div> <p>The sample above might be corrected to the following code:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">static</span> <span class="dt">bool</span> IsPositive(<span class="dt">int</span> i) { <span class="kw">return</span> i &gt; <span class="dv">0</span>; } <span class="dt">bool</span> *ABCIsNegative(<span class="dt">int</span> i) { <span class="kw">return</span> i &lt; <span class="dv">0</span>; }</code></pre></div> <p>(Clang-Tidy original name: google-objc-function-naming)</p> + + + + Major + + + + + + + false + false + google-objc-global-variable-declaration + google + + true + Objc Global Variable Declaration + <p>Finds global variable declarations in Objective-C files that do not follow the pattern of variable names in Google’s Objective-C Style Guide.</p> <p>The corresponding style guide rule: <a href="https://google.github.io/styleguide/objcguide.html\#variable-names" class="uri">https://google.github.io/styleguide/objcguide.html\#variable-names</a></p> <p>All the global variables should follow the pattern of g[A-Z].* (variables) or k[A-Z].* (constants). The check will suggest a variable name that follows the pattern if it can be inferred from the original name.</p> <p>For code:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">static</span> NSString* myString = <span class="er">@</span><span class="st">&quot;hello&quot;</span>;</code></pre></div> <p>The fix will be:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">static</span> NSString* gMyString = <span class="er">@</span><span class="st">&quot;hello&quot;</span>;</code></pre></div> <p>Another example of constant:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">static</span> NSString* <span class="dt">const</span> myConstString = <span class="er">@</span><span class="st">&quot;hello&quot;</span>;</code></pre></div> <p>The fix will be:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">static</span> NSString* <span class="dt">const</span> kMyConstString = <span class="er">@</span><span class="st">&quot;hello&quot;</span>;</code></pre></div> <p>However for code that prefixed with non-alphabetical characters like:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">static</span> NSString* __anotherString = <span class="er">@</span><span class="st">&quot;world&quot;</span>;</code></pre></div> <p>The check will give a warning message but will not be able to suggest a fix. The user needs to fix it on their own.</p> <p>(Clang-Tidy original name: google-objc-global-variable-declaration)</p> + + + + Major + + + + + + + false + false + google-readability-avoid-underscore-in-googletest-name + google + + true + Readability Avoid Underscore In Googletest Name + <p>Checks whether there are underscores in googletest test and test case names in test macros:</p> <ul> <li>TEST</li> <li>TEST_F</li> <li>TEST_P</li> <li>TYPED_TEST</li> <li>TYPED_TEST_P</li> </ul> <p>The FRIEND_TEST macro is not included.</p> <p>For example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">TEST(TestCaseName, Illegal_TestName) {} TEST(Illegal_TestCaseName, TestName) {}</code></pre></div> <p>would trigger the check. <a href="https://github.com/google/googletest/blob/master/googletest/docs/faq.md#why-should-test-suite-names-and-test-names-not-contain-underscore">Underscores are not allowed</a> in test names nor test case names.</p> <p>The DISABLED_ prefix, which may be used to <a href="https://github.com/google/googletest/blob/master/googletest/docs/faq.md#why-should-test-suite-names-and-test-names-not-contain-underscore">disable individual tests</a>, is ignored when checking test names, but the rest of the rest of the test name is still checked.</p> <p>This check does not propose any fixes.</p> <p>(Clang-Tidy original name: google-readability-avoid-underscore-in-googletest-name)</p> + + + + Major + + + + + + + false + false + google-readability-braces-around-statements + google + + true + Readability Braces Around Statements + <p>The google-readability-braces-around-statements check is an alias, please see <a href="readability-braces-around-statements.html">readability-braces-around-statements</a> for more information.</p> <p>(Clang-Tidy original name: google-readability-braces-around-statements)</p> + + + + Major + + + + + + + false + false + google-readability-casting + google + + true + Readability Casting + <p>Finds usages of C-style casts.</p> <p><a href="https://google.github.io/styleguide/cppguide.html\#Casting" class="uri">https://google.github.io/styleguide/cppguide.html\#Casting</a></p> <p>Corresponding cpplint.py check name: readability/casting.</p> <p>This check is similar to -Wold-style-cast, but it suggests automated fixes in some cases. The reported locations should not be different from the ones generated by -Wold-style-cast.</p> <p>(Clang-Tidy original name: google-readability-casting)</p> + + + + Major + + + + + + + false + false + google-readability-function-size + google + + true + Readability Function Size + <p>The google-readability-function-size check is an alias, please see <a href="readability-function-size.html">readability-function-size</a> for more information.</p> <p>(Clang-Tidy original name: google-readability-function-size)</p> + + + + Major + + + + + + + false + false + google-runtime-int + google + + true + Runtime Int + <p>Finds uses of short, long and long long and suggest replacing them with u?intXX(_t)?.</p> <p>The corresponding style guide rule: <a href="https://google.github.io/styleguide/cppguide.html\#Integer_Types" class="uri">https://google.github.io/styleguide/cppguide.html\#Integer_Types</a>.</p> <p>Corresponding cpplint.py check: runtime/int.</p> <h5 id="options-45">Options</h5> <p>UnsignedTypePrefix</p> <p>A string specifying the unsigned type prefix. Default is uint.</p> <p>SignedTypePrefix</p> <p>A string specifying the signed type prefix. Default is int.</p> <p>TypeSuffix</p> <p>A string specifying the type suffix. Default is an empty string.</p> <p>(Clang-Tidy original name: google-runtime-int)</p> + + + + Major + + + + + + + false + false + google-readability-namespace-comments + google + + true + Readability Namespace Comments + <p>The google-readability-namespace-comments check is an alias, please see <a href="llvm-namespace-comment.html">llvm-namespace-comment</a> for more information.</p> <p>(Clang-Tidy original name: google-readability-namespace-comments)</p> + + + + Major + + + + + + + false + false + google-runtime-operator + google + + true + Runtime Operator + <p>Finds overloads of unary operator &amp;.</p> <p><a href="https://google.github.io/styleguide/cppguide.html\#Operator_Overloading" class="uri">https://google.github.io/styleguide/cppguide.html\#Operator_Overloading</a></p> <p>Corresponding cpplint.py check name: runtime/operator.</p> <p>(Clang-Tidy original name: google-runtime-operator)</p> + + + + Major + + + + + + + false + false + google-readability-todo + google + + true + Readability Todo + <p>Finds TODO comments without a username or bug number.</p> <p>The relevant style guide section is <a href="https://google.github.io/styleguide/cppguide.html\#TODO_Comments" class="uri">https://google.github.io/styleguide/cppguide.html\#TODO_Comments</a>.</p> <p>Corresponding cpplint.py check: readability/todo</p> <p>(Clang-Tidy original name: google-readability-todo)</p> + + + + Major + + + + + + + false + false + google-upgrade-googletest-case + google + + true + Upgrade Googletest Case + <p>Finds uses of deprecated Google Test version 1.9 APIs with names containing case and replaces them with equivalent APIs with suite.</p> <p>All names containing case are being replaced to be consistent with the meanings of “test case” and “test suite” as used by the International Software Testing Qualifications Board and ISO 29119.</p> <p>The new names are a part of Google Test version 1.9 (release pending). It is recommended that users update their dependency to version 1.9 and then use this check to remove deprecated names.</p> <p>The affected APIs are:</p> <ul> <li>Member functions of testing::Test, testing::TestInfo, testing::TestEventListener, testing::UnitTest, and any type inheriting from these types</li> <li>The macros TYPED_TEST_CASE, TYPED_TEST_CASE_P, REGISTER_TYPED_TEST_CASE_P, and INSTANTIATE_TYPED_TEST_CASE_P</li> <li>The type alias testing::TestCase</li> </ul> <p>Examples of fixes created by this check:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> FooTest : <span class="kw">public</span> testing::Test { <span class="kw">public</span>: <span class="dt">static</span> <span class="dt">void</span> SetUpTestCase(); <span class="dt">static</span> <span class="dt">void</span> TearDownTestCase(); }; TYPED_TEST_CASE(BarTest, BarTypes);</code></pre></div> <p>becomes</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> FooTest : <span class="kw">public</span> testing::Test { <span class="kw">public</span>: <span class="dt">static</span> <span class="dt">void</span> SetUpTestSuite(); <span class="dt">static</span> <span class="dt">void</span> TearDownTestSuite(); }; TYPED_TEST_SUITE(BarTest, BarTypes);</code></pre></div> <p>For better consistency of user code, the check renames both virtual and non-virtual member functions with matching names in derived types. The check tries to provide a only warning when a fix cannot be made safely, as is the case with some template and macro uses.</p> <p>(Clang-Tidy original name: google-upgrade-googletest-case)</p> + + + + Major + + + + + + + false + false + hicpp-avoid-c-arrays + hicpp + + true + Avoid C Arrays + <p>The hicpp-avoid-c-arrays check is an alias, please see <a href="modernize-avoid-c-arrays.html">modernize-avoid-c-arrays</a> for more information.</p> <p>(Clang-Tidy original name: hicpp-avoid-c-arrays)</p> + + + + Major + + + + + + + false + false + hicpp-avoid-goto + hicpp + + true + Avoid Goto + <p>The hicpp-avoid-goto check is an alias to <a href="cppcoreguidelines-avoid-goto.html">cppcoreguidelines-avoid-goto</a>. Rule <a href="http://www.codingstandard.com/rule/6-3-1-ensure-that-the-labels-for-a-jump-statement-or-a-switch-condition-appear-later-in-the-same-or-an-enclosing-block/">6.3.1 High Integrity C++</a> requires that goto only skips parts of a block and is not used for other reasons.</p> <p>Both coding guidelines implement the same exception to the usage of goto.</p> <p>(Clang-Tidy original name: hicpp-avoid-goto)</p> + + + + Major + + + + + + + false + false + hicpp-braces-around-statements + hicpp + + true + Braces Around Statements + <p>The hicpp-braces-around-statements check is an alias, please see <a href="readability-braces-around-statements.html">readability-braces-around-statements</a> for more information. It enforces the <a href="http://www.codingstandard.com/rule/6-1-1-enclose-the-body-of-a-selection-or-an-iteration-statement-in-a-compound-statement/">rule 6.1.1</a>.</p> <p>(Clang-Tidy original name: hicpp-braces-around-statements)</p> + + + + Major + + + + + + + false + false + hicpp-deprecated-headers + hicpp + + true + Deprecated Headers + <p>The hicpp-deprecated-headers check is an alias, please see <a href="modernize-deprecated-headers.html">modernize-deprecated-headers</a> for more information. It enforces the <a href="http://www.codingstandard.com/rule/1-3-3-do-not-use-the-c-standard-library-h-headers/">rule 1.3.3</a>.</p> <p>(Clang-Tidy original name: hicpp-deprecated-headers)</p> + + + + Major + + + + + + + false + false + hicpp-exception-baseclass + hicpp + + true + Exception Baseclass + <p>Ensure that every value that in a throw expression is an instance of std::exception.</p> <p>This enforces <a href="http://www.codingstandard.com/section/15-1-throwing-an-exception/">rule 15.1</a> of the High Integrity C++ Coding Standard.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> custom_exception {}; <span class="dt">void</span> throwing() <span class="kw">noexcept</span>(<span class="kw">false</span>) { <span class="co">// Problematic throw expressions.</span> <span class="kw">throw</span> <span class="dt">int</span>(<span class="dv">42</span>); <span class="kw">throw</span> custom_exception(); } <span class="kw">class</span> mathematical_error : <span class="kw">public</span> std::exception {}; <span class="dt">void</span> throwing2() <span class="kw">noexcept</span>(<span class="kw">false</span>) { <span class="co">// These kind of throws are ok.</span> <span class="kw">throw</span> mathematical_error(); <span class="kw">throw</span> std::runtime_error(); <span class="kw">throw</span> std::exception(); }</code></pre></div> <p>(Clang-Tidy original name: hicpp-exception-baseclass)</p> + + + + Major + + + + + + + false + false + hicpp-explicit-conversions + hicpp + + true + Explicit Conversions + <p>This check is an alias for <a href="google-explicit-constructor.html">google-explicit-constructor</a>. Used to enforce parts of <a href="http://www.codingstandard.com/rule/5-4-1-only-use-casting-forms-static_cast-excl-void-dynamic_cast-or-explicit-constructor-call/">rule 5.4.1</a>. This check will enforce that constructors and conversion operators are marked explicit. Other forms of casting checks are implemented in other places. The following checks can be used to check for more forms of casting:</p> <ul> <li><a href="cppcoreguidelines-pro-type-static-cast-downcast.html">cppcoreguidelines-pro-type-static-cast-downcast</a></li> <li><a href="cppcoreguidelines-pro-type-reinterpret-cast.html">cppcoreguidelines-pro-type-reinterpret-cast</a></li> <li><a href="cppcoreguidelines-pro-type-const-cast.html">cppcoreguidelines-pro-type-const-cast</a></li> <li><a href="cppcoreguidelines-pro-type-cstyle-cast.html">cppcoreguidelines-pro-type-cstyle-cast</a></li> </ul> <p>(Clang-Tidy original name: hicpp-explicit-conversions)</p> + + + + Major + + + + + + + false + false + hicpp-function-size + hicpp + + true + Function Size + <p>This check is an alias for <a href="readability-function-size.html">readability-function-size</a>. Useful to enforce multiple sections on function complexity.</p> <ul> <li><a href="http://www.codingstandard.com/rule/8-2-2-do-not-declare-functions-with-an-excessive-number-of-parameters/">rule 8.2.2</a></li> <li><a href="http://www.codingstandard.com/rule/8-3-1-do-not-write-functions-with-an-excessive-mccabe-cyclomatic-complexity/">rule 8.3.1</a></li> <li><a href="http://www.codingstandard.com/rule/8-3-2-do-not-write-functions-with-a-high-static-program-path-count/">rule 8.3.2</a></li> </ul> <p>(Clang-Tidy original name: hicpp-function-size)</p> + + + + Major + + + + + + + false + false + hicpp-invalid-access-moved + hicpp + + true + Invalid Access Moved + <p>This check is an alias for <a href="bugprone-use-after-move.html">bugprone-use-after-move</a>.</p> <p>Implements parts of the <a href="http://www.codingstandard.com/rule/8-4-1-do-not-access-an-invalid-object-or-an-object-with-indeterminate-value/">rule 8.4.1</a> to check if moved-from objects are accessed.</p> <p>(Clang-Tidy original name: hicpp-invalid-access-moved)</p> + + + + Major + + + + + + + false + false + hicpp-move-const-arg + hicpp + + true + Move Const Arg + <p>The hicpp-move-const-arg check is an alias, please see <a href="performance-move-const-arg.html">performance-move-const-arg</a> for more information. It enforces the <a href="http://www.codingstandard.com/rule/17-3-1-do-not-use-stdmove-on-objects-declared-with-const-or-const-type/">rule 17.3.1</a>.</p> <p>(Clang-Tidy original name: hicpp-move-const-arg)</p> + + + + Major + + + + + + + false + false + hicpp-member-init + hicpp + + true + Member Init + <p>This check is an alias for <a href="cppcoreguidelines-pro-type-member-init.html">cppcoreguidelines-pro-type-member-init</a>. Implements the check for <a href="http://www.codingstandard.com/rule/12-4-2-ensure-that-a-constructor-initializes-explicitly-all-base-classes-and-non-static-data-members/">rule 12.4.2</a> to initialize class members in the right order.</p> <p>(Clang-Tidy original name: hicpp-member-init)</p> + + + + Major + + + + + + + false + false + hicpp-multiway-paths-covered + hicpp + + true + Multiway Paths Covered + <p>This check discovers situations where code paths are not fully-covered. It furthermore suggests using if instead of switch if the code will be more clear. The <a href="http://www.codingstandard.com/rule/6-1-2-explicitly-cover-all-paths-through-multi-way-selection-statements/">rule 6.1.2</a> and <a href="http://www.codingstandard.com/rule/6-1-4-ensure-that-a-switch-statement-has-at-least-two-case-labels-distinct-from-the-default-label/">rule 6.1.4</a> of the High Integrity C++ Coding Standard are enforced.</p> <p>if-else if chains that miss a final else branch might lead to unexpected program execution and be the result of a logical error. If the missing else branch is intended you can leave it empty with a clarifying comment. This warning can be noisy on some code bases, so it is disabled by default.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> f1() { <span class="dt">int</span> i = determineTheNumber(); <span class="kw">if</span>(i &gt; <span class="dv">0</span>) { <span class="co">// Some Calculation</span> } <span class="kw">else</span> <span class="kw">if</span> (i &lt; <span class="dv">0</span>) { <span class="co">// Precondition violated or something else.</span> } <span class="co">// ...</span> }</code></pre></div> <p>Similar arguments hold for switch statements which do not cover all possible code paths.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// The missing default branch might be a logical error. It can be kept empty</span> <span class="co">// if there is nothing to do, making it explicit.</span> <span class="dt">void</span> f2(<span class="dt">int</span> i) { <span class="kw">switch</span> (i) { <span class="kw">case</span> <span class="dv">0</span>: <span class="co">// something</span> <span class="kw">break</span>; <span class="kw">case</span> <span class="dv">1</span>: <span class="co">// something else</span> <span class="kw">break</span>; } <span class="co">// All other numbers?</span> } <span class="co">// Violates this rule as well, but already emits a compiler warning (-Wswitch).</span> <span class="kw">enum</span> Color { Red, Green, Blue, Yellow }; <span class="dt">void</span> f3(<span class="kw">enum</span> Color c) { <span class="kw">switch</span> (c) { <span class="kw">case</span> Red: <span class="co">// We can&#39;t drive for now.</span> <span class="kw">break</span>; <span class="kw">case</span> Green: <span class="co">// We are allowed to drive.</span> <span class="kw">break</span>; } <span class="co">// Other cases missing</span> }</code></pre></div> <p>The <a href="http://www.codingstandard.com/rule/6-1-4-ensure-that-a-switch-statement-has-at-least-two-case-labels-distinct-from-the-default-label/">rule 6.1.4</a> requires every switch statement to have at least two case labels other than a default label. Otherwise, the switch could be better expressed with an if statement. Degenerated switch statements without any labels are caught as well.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Degenerated switch that could be better written as `if`</span> <span class="dt">int</span> i = <span class="dv">42</span>; <span class="kw">switch</span>(i) { <span class="kw">case</span> <span class="dv">1</span>: <span class="co">// do something here</span> <span class="kw">default</span>: <span class="co">// do somethe else here</span> } <span class="co">// Should rather be the following:</span> <span class="kw">if</span> (i == <span class="dv">1</span>) { <span class="co">// do something here</span> } <span class="kw">else</span> { <span class="co">// do something here</span> }</code></pre></div> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// A completely degenerated switch will be diagnosed.</span> <span class="dt">int</span> i = <span class="dv">42</span>; <span class="kw">switch</span>(i) {}</code></pre></div> <h5 id="options-80">Options</h5> <p>WarnOnMissingElse</p> <p>Boolean flag that activates a warning for missing else branches. Default is false.</p> <p>(Clang-Tidy original name: hicpp-multiway-paths-covered)</p> + + + + Major + + + + + + + false + false + hicpp-no-assembler + hicpp + + true + No Assembler + <p>Check for assembler statements. No fix is offered.</p> <p>Inline assembler is forbidden by the <a href="http://www.codingstandard.com/section/7-5-the-asm-declaration/">High Intergrity C++ Coding Standard</a> as it restricts the portability of code.</p> <p>(Clang-Tidy original name: hicpp-no-assembler)</p> + + + + Major + + + + + + + false + false + hicpp-no-array-decay + hicpp + + true + No Array Decay + <p>The hicpp-no-array-decay check is an alias, please see <a href="cppcoreguidelines-pro-bounds-array-to-pointer-decay.html">cppcoreguidelines-pro-bounds-array-to-pointer-decay</a> for more information. It enforces the <a href="http://www.codingstandard.com/section/4-1-array-to-pointer-conversion/">rule 4.1.1</a>.</p> <p>(Clang-Tidy original name: hicpp-no-array-decay)</p> + + + + Major + + + + + + + false + false + hicpp-new-delete-operators + hicpp + + true + New Delete Operators + <p>This check is an alias for <a href="misc-new-delete-overloads.html">misc-new-delete-overloads</a>. Implements <a href="http://www.codingstandard.com/section/12-3-free-store/">rule 12.3.1</a> to ensure the new and delete operators have the correct signature.</p> <p>(Clang-Tidy original name: hicpp-new-delete-operators)</p> + + + + Major + + + + + + + false + false + hicpp-noexcept-move + hicpp + + true + Noexcept Move + <p>This check is an alias for <a href="performance-noexcept-move-constructor.html">performance-noexcept-move-constructor</a>. Checks <a href="http://www.codingstandard.com/rule/12-5-4-declare-noexcept-the-move-constructor-and-move-assignment-operator">rule 12.5.4</a> to mark move assignment and move construction noexcept.</p> <p>(Clang-Tidy original name: hicpp-noexcept-move)</p> + + + + Major + + + + + + + false + false + hicpp-no-malloc + hicpp + + true + No Malloc + <p>The hicpp-no-malloc check is an alias, please see <a href="cppcoreguidelines-no-malloc.html">cppcoreguidelines-no-malloc</a> for more information. It enforces the <a href="http://www.codingstandard.com/rule/5-3-2-allocate-memory-using-new-and-release-it-using-delete/">rule 5.3.2</a>.</p> <p>(Clang-Tidy original name: hicpp-no-malloc)</p> + + + + Major + + + + + + + false + false + hicpp-named-parameter + hicpp + + true + Named Parameter + <p>This check is an alias for <a href="readability-named-parameter.html">readability-named-parameter</a>.</p> <p>Implements <a href="http://www.codingstandard.com/rule/8-2-1-make-parameter-names-absent-or-identical-in-all-declarations/">rule 8.2.1</a>.</p> <p>(Clang-Tidy original name: hicpp-named-parameter)</p> + + + + Major + + + + + + + false + false + hicpp-static-assert + hicpp + + true + Static Assert + <p>The hicpp-static-assert check is an alias, please see <a href="misc-static-assert.html">misc-static-assert</a> for more information. It enforces the <a href="http://www.codingstandard.com/rule/6-1-1-enclose-the-body-of-a-selection-or-an-iteration-statement-in-a-compound-statement/">rule 7.1.10</a>.</p> <p>(Clang-Tidy original name: hicpp-static-assert)</p> + + + + Major + + + + + + + false + false + hicpp-signed-bitwise + hicpp + + true + Signed Bitwise + <p>Finds uses of bitwise operations on signed integer types, which may lead to undefined or implementation defined behaviour.</p> <p>The according rule is defined in the <a href="http://www.codingstandard.com/section/5-6-shift-operators/">High Integrity C++ Standard, Section 5.6.1</a>.</p> <h5 id="options-6">Options</h5> <p>IgnorePositiveIntegerLiterals</p> <p>If this option is set to true, the check will not warn on bitwise operations with positive integer literals, e.g. ~0, 2 &lt;&lt; 1, etc. Default value is false.</p> <p>(Clang-Tidy original name: hicpp-signed-bitwise)</p> + + + + Major + + + + + + + false + false + hicpp-special-member-functions + hicpp + + true + Special Member Functions + <p>This check is an alias for <a href="cppcoreguidelines-special-member-functions.html">cppcoreguidelines-special-member-functions</a>. Checks that special member functions have the correct signature, according to <a href="http://www.codingstandard.com/rule/12-5-7-declare-assignment-operators-with-the-ref-qualifier/">rule 12.5.7</a>.</p> <p>(Clang-Tidy original name: hicpp-special-member-functions)</p> + + + + Major + + + + + + + false + false + hicpp-use-auto + hicpp + + true + Use Auto + <p>The hicpp-use-auto check is an alias, please see <a href="modernize-use-auto.html">modernize-use-auto</a> for more information. It enforces the <a href="http://www.codingstandard.com/rule/7-1-8-use-auto-id-expr-when-declaring-a-variable-to-have-the-same-type-as-its-initializer-function-call/">rule 7.1.8</a>.</p> <p>(Clang-Tidy original name: hicpp-use-auto)</p> + + + + Major + + + + + + + false + false + hicpp-undelegated-constructor + hicpp + + true + Undelegated Constructor + <p>This check is an alias for <a href="bugprone-undelegated-constructor.html">bugprone-undelegated-constructor</a>. Partially implements <a href="http://www.codingstandard.com/rule/12-4-5-use-delegating-constructors-to-reduce-code-duplication/">rule 12.4.5</a> to find misplaced constructor calls inside a constructor.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> Ctor { Ctor(); Ctor(<span class="dt">int</span>); Ctor(<span class="dt">int</span>, <span class="dt">int</span>); Ctor(Ctor *i) { <span class="co">// All Ctor() calls result in a temporary object</span> Ctor(); <span class="co">// did you intend to call a delegated constructor?</span> Ctor(<span class="dv">0</span>); <span class="co">// did you intend to call a delegated constructor?</span> Ctor(<span class="dv">1</span>, <span class="dv">2</span>); <span class="co">// did you intend to call a delegated constructor?</span> foo(); } };</code></pre></div> <p>(Clang-Tidy original name: hicpp-undelegated-constructor)</p> + + + + Major + + + + + + + false + false + hicpp-use-emplace + hicpp + + true + Use Emplace + <p>The hicpp-use-emplace check is an alias, please see <a href="modernize-use-emplace.html">modernize-use-emplace</a> for more information. It enforces the <a href="http://www.codingstandard.com/rule/17-4-2-use-api-calls-that-construct-objects-in-place/">rule 17.4.2</a>.</p> <p>(Clang-Tidy original name: hicpp-use-emplace)</p> + + + + Major + + + + + + + false + false + hicpp-use-equals-default + hicpp + + true + Use Equals Default + <p>This check is an alias for <a href="modernize-use-equals-default.html">modernize-use-equals-default</a>. Implements <a href="http://www.codingstandard.com/rule/12-5-1-define-explicitly-default-or-delete-implicit-special-member-functions-of-concrete-classes/">rule 12.5.1</a> to explicitly default special member functions.</p> <p>(Clang-Tidy original name: hicpp-use-equals-default)</p> + + + + Major + + + + + + + false + false + hicpp-use-equals-delete + hicpp + + true + Use Equals Delete + <p>This check is an alias for <a href="modernize-use-equals-delete.html">modernize-use-equals-delete</a>. Implements <a href="http://www.codingstandard.com/rule/12-5-1-define-explicitly-default-or-delete-implicit-special-member-functions-of-concrete-classes/">rule 12.5.1</a> to explicitly default or delete special member functions.</p> <p>(Clang-Tidy original name: hicpp-use-equals-delete)</p> + + + + Major + + + + + + + false + false + hicpp-uppercase-literal-suffix + hicpp + + true + Uppercase Literal Suffix + <p>The hicpp-uppercase-literal-suffix check is an alias, please see <a href="readability-uppercase-literal-suffix.html">readability-uppercase-literal-suffix</a> for more information.</p> <p>(Clang-Tidy original name: hicpp-uppercase-literal-suffix)</p> + + + + Major + + + + + + + false + false + hicpp-use-noexcept + hicpp + + true + Use Noexcept + <p>The hicpp-use-noexcept check is an alias, please see <a href="modernize-use-noexcept.html">modernize-use-noexcept</a> for more information. It enforces the <a href="http://www.codingstandard.com/rule/1-3-5-do-not-use-throw-exception-specifications/">rule 1.3.5</a>.</p> <p>(Clang-Tidy original name: hicpp-use-noexcept)</p> + + + + Major + + + + + + + false + false + hicpp-use-nullptr + hicpp + + true + Use Nullptr + <p>The hicpp-use-nullptr check is an alias, please see <a href="modernize-use-nullptr.html">modernize-use-nullptr</a> for more information. It enforces the <a href="http://www.codingstandard.com/rule/2-5-3-use-nullptr-for-the-null-pointer-constant/">rule 2.5.3</a>.</p> <p>(Clang-Tidy original name: hicpp-use-nullptr)</p> + + + + Major + + + + + + + false + false + hicpp-use-override + hicpp + + true + Use Override + <p>This check is an alias for <a href="modernize-use-override.html">modernize-use-override</a>. Implements <a href="http://www.codingstandard.com/section/10-2-virtual-functions/">rule 10.2.1</a> to declare a virtual function override when overriding.</p> <p>(Clang-Tidy original name: hicpp-use-override)</p> + + + + Major + + + + + + + false + false + hicpp-vararg + hicpp + + true + Vararg + <p>The hicpp-vararg check is an alias, please see <a href="cppcoreguidelines-pro-type-vararg.html">cppcoreguidelines-pro-type-vararg</a> for more information. It enforces the <a href="http://www.codingstandard.com/section/14-1-template-declarations/">rule 14.1.1</a>.</p> <p>(Clang-Tidy original name: hicpp-vararg)</p> + + + + Major + + + + + + + false + false + linuxkernel-must-check-errs + linuxkernel + + true + Must Check Errs + <p>Checks Linux kernel code to see if it uses the results from the functions in linux/err.h. Also checks to see if code uses the results from functions that directly return a value from one of these error functions.</p> <p>This is important in the Linux kernel because ERR_PTR, PTR_ERR, IS_ERR, IS_ERR_OR_NULL, ERR_CAST, and PTR_ERR_OR_ZERO return values must be checked, since positive pointers and negative error codes are being used in the same context. These functions are marked with <strong>attribute</strong>((warn_unused_result)), but some kernel versions do not have this warning enabled for clang.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">/* Trivial unused call to an ERR function */</span> PTR_ERR_OR_ZERO(some_function_call()); <span class="co">/* A function that returns ERR_PTR. */</span> <span class="dt">void</span> *fn() { ERR_PTR(-EINVAL); } <span class="co">/* An invalid use of fn. */</span> fn();</code></pre></div> <p>(Clang-Tidy original name: linuxkernel-must-check-errs)</p> + + + + Major + + + + + + + false + false + llvmlibc-callee-namespace + llvmlibc + + true + Callee Namespace + <p>Checks all calls resolve to functions within __llvm_libc namespace.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">namespace</span> __llvm_libc { <span class="co">// Allow calls with the fully qualified name.</span> __llvm_libc::strlen(<span class="st">&quot;hello&quot;</span>); <span class="co">// Allow calls to compiler provided functions.</span> (<span class="dt">void</span>)<span class="ot">__builtin_abs</span>(<span class="dv">-1</span>); <span class="co">// Bare calls are allowed as long as they resolve to the correct namespace.</span> strlen(<span class="st">&quot;world&quot;</span>); <span class="co">// Disallow calling into functions in the global namespace.</span> ::strlen(<span class="st">&quot;!&quot;</span>); } <span class="co">// namespace __llvm_libc</span></code></pre></div> <p>(Clang-Tidy original name: llvmlibc-callee-namespace)</p> + + + + Major + + + + + + + false + false + llvmlibc-implementation-in-namespace + llvmlibc + + true + Implementation In Namespace + <p>Checks that all declarations in the llvm-libc implementation are within the correct namespace.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Correct: implementation inside the correct namespace.</span> <span class="kw">namespace</span> __llvm_libc { <span class="dt">void</span> LLVM_LIBC_ENTRYPOINT(strcpy)(<span class="dt">char</span> *dest, <span class="dt">const</span> <span class="dt">char</span> *src) {} <span class="co">// Namespaces within __llvm_libc namespace are allowed.</span> <span class="kw">namespace</span> inner{ <span class="dt">int</span> localVar = <span class="dv">0</span>; } <span class="co">// Functions with C linkage are allowed.</span> <span class="dt">extern</span> <span class="st">&quot;C&quot;</span> <span class="dt">void</span> str_fuzz(){} } <span class="co">// Incorrect: implementation not in a namespace.</span> <span class="dt">void</span> LLVM_LIBC_ENTRYPOINT(strcpy)(<span class="dt">char</span> *dest, <span class="dt">const</span> <span class="dt">char</span> *src) {} <span class="co">// Incorrect: outer most namespace is not correct.</span> <span class="kw">namespace</span> something_else { <span class="dt">void</span> LLVM_LIBC_ENTRYPOINT(strcpy)(<span class="dt">char</span> *dest, <span class="dt">const</span> <span class="dt">char</span> *src) {} }</code></pre></div> <p>(Clang-Tidy original name: llvmlibc-implementation-in-namespace)</p> + + + + Major + + + + + + + false + false + llvmlibc-restrict-system-libc-headers + llvmlibc + + true + Restrict System Libc Headers + <p>Finds includes of system libc headers not provided by the compiler within llvm-libc implementations.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#include &lt;stdio.h&gt; </span><span class="co">// Not allowed because it is part of system libc.</span> <span class="ot">#include &lt;stddef.h&gt; </span><span class="co">// Allowed because it is provided by the compiler.</span> <span class="ot">#include &quot;internal/stdio.h&quot; </span><span class="co">// Allowed because it is NOT part of system libc.</span></code></pre></div> <p>This check is necessary because accidentally including system libc headers can lead to subtle and hard to detect bugs. For example consider a system libc whose dirent struct has slightly different field ordering than llvm-libc. While this will compile successfully, this can cause issues during runtime because they are ABI incompatible.</p> <h5 id="options-22">Options</h5> <p>Includes</p> <p>A string containing a comma separated glob list of allowed include filenames. Similar to the -checks glob list for running clang-tidy itself, the two wildcard characters are * and -, to include and exclude globs, respectively. The default is -*, which disallows all includes.</p> <p>This can be used to allow known safe includes such as Linux development headers. See <a href="portability-restrict-system-includes.html">portability-restrict-system-includes</a> for more details.</p> <p>(Clang-Tidy original name: llvmlibc-restrict-system-libc-headers)</p> + + + + Major + + + + + + + false + false + llvm-else-after-return + llvm + + true + Else After Return + <p>The llvm-else-after-return check is an alias, please see <a href="readability-else-after-return.html">readability-else-after-return</a> for more information.</p> <p>(Clang-Tidy original name: llvm-else-after-return)</p> + + + + Major + + + + + + + false + false + llvm-header-guard + llvm + + true + Header Guard + <p>Finds and fixes header guards that do not adhere to LLVM style.</p> <h5 id="options-7">Options</h5> <p>HeaderFileExtensions</p> <p>A comma-separated list of filename extensions of header files (the filename extensions should not include “.” prefix). Default is “h,hh,hpp,hxx”. For header files without an extension, use an empty string (if there are no other desired extensions) or leave an empty element in the list. e.g., “h,hh,hpp,hxx,” (note the trailing comma).</p> <p>(Clang-Tidy original name: llvm-header-guard)</p> + + + + Major + + + + + + + false + false + llvm-include-order + llvm + + true + Include Order + <p>Checks the correct order of #includes.</p> <p>See <a href="https://llvm.org/docs/CodingStandards.html\#include-style" class="uri">https://llvm.org/docs/CodingStandards.html\#include-style</a></p> <p>(Clang-Tidy original name: llvm-include-order)</p> + + + + Major + + + + + + + false + false + llvm-namespace-comment + llvm + + true + Namespace Comment + <p>google-readability-namespace-comments redirects here as an alias for this check.</p> <p>Checks that long namespaces have a closing comment.</p> <p><a href="https://llvm.org/docs/CodingStandards.html\#namespace-indentation" class="uri">https://llvm.org/docs/CodingStandards.html\#namespace-indentation</a></p> <p><a href="https://google.github.io/styleguide/cppguide.html\#Namespaces" class="uri">https://google.github.io/styleguide/cppguide.html\#Namespaces</a></p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">namespace</span> n1 { <span class="dt">void</span> f(); } <span class="co">// becomes</span> <span class="kw">namespace</span> n1 { <span class="dt">void</span> f(); } <span class="co">// namespace n1</span></code></pre></div> <h5 id="options-78">Options</h5> <p>ShortNamespaceLines</p> <p>Requires the closing brace of the namespace definition to be followed by a closing comment if the body of the namespace has more than ShortNamespaceLines lines of code. The value is an unsigned integer that defaults to 1U.</p> <p>SpacesBeforeComments</p> <p>An unsigned integer specifying the number of spaces before the comment closing a namespace definition. Default is 1U.</p> <p>(Clang-Tidy original name: llvm-namespace-comment)</p> + + + + Major + + + + + + + false + false + llvm-prefer-isa-or-dyn-cast-in-conditionals + llvm + + true + Prefer Isa Or Dyn Cast In Conditionals + <p>Looks at conditionals and finds and replaces cases of cast&lt;&gt;, which will assert rather than return a null pointer, and dyn_cast&lt;&gt; where the return value is not captured. Additionally, finds and replaces cases that match the pattern var &amp;&amp; isa<X>(var), where var is evaluated twice.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Finds these:</span> <span class="kw">if</span> (<span class="kw">auto</span> x = cast&lt;X&gt;(y)) {} <span class="co">// is replaced by:</span> <span class="kw">if</span> (<span class="kw">auto</span> x = dyn_cast&lt;X&gt;(y)) {} <span class="kw">if</span> (cast&lt;X&gt;(y)) {} <span class="co">// is replaced by:</span> <span class="kw">if</span> (isa&lt;X&gt;(y)) {} <span class="kw">if</span> (dyn_cast&lt;X&gt;(y)) {} <span class="co">// is replaced by:</span> <span class="kw">if</span> (isa&lt;X&gt;(y)) {} <span class="kw">if</span> (var &amp;&amp; isa&lt;T&gt;(var)) {} <span class="co">// is replaced by:</span> <span class="kw">if</span> (isa_and_nonnull&lt;T&gt;(var.foo())) {} <span class="co">// Other cases are ignored, e.g.:</span> <span class="kw">if</span> (<span class="kw">auto</span> f = cast&lt;Z&gt;(y)-&gt;foo()) {} <span class="kw">if</span> (cast&lt;Z&gt;(y)-&gt;foo()) {} <span class="kw">if</span> (X.cast(y)) {}</code></pre></div> <p>(Clang-Tidy original name: llvm-prefer-isa-or-dyn-cast-in-conditionals)</p> + + + + Major + + + + + + + false + false + llvm-prefer-register-over-unsigned + llvm + + true + Prefer Register Over Unsigned + <p>Finds historical use of unsigned to hold vregs and physregs and rewrites them to use Register.</p> <p>Currently this works by finding all variables of unsigned integer type whose initializer begins with an implicit cast from Register to unsigned.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> example(MachineOperand &amp;MO) { <span class="dt">unsigned</span> Reg = MO.getReg(); ... }</code></pre></div> <p>becomes:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> example(MachineOperand &amp;MO) { Register Reg = MO.getReg(); ... }</code></pre></div> <p>(Clang-Tidy original name: llvm-prefer-register-over-unsigned)</p> + + + + Major + + + + + + + false + false + llvm-qualified-auto + llvm + + true + Qualified Auto + <p>The llvm-qualified-auto check is an alias, please see <a href="readability-qualified-auto.html">readability-qualified-auto</a> for more information.</p> <p>(Clang-Tidy original name: llvm-qualified-auto)</p> + + + + Major + + + + + + + false + false + llvm-twine-local + llvm + + true + Twine Local + <p>Looks for local Twine variables which are prone to use after frees and should be generally avoided.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">static</span> Twine Moo = Twine(<span class="st">&quot;bark&quot;</span>) + <span class="st">&quot;bah&quot;</span>; <span class="co">// becomes</span> <span class="dt">static</span> std::string Moo = (Twine(<span class="st">&quot;bark&quot;</span>) + <span class="st">&quot;bah&quot;</span>).str();</code></pre></div> <p>(Clang-Tidy original name: llvm-twine-local)</p> + + + + Major + + + + + + + true + false + modernize-avoid-bind + modernize + + true + Avoid Bind + <p>The check finds uses of std::bind and boost::bind and replaces them with lambdas. Lambdas will use value-capture unless reference capture is explicitly requested with std::ref or boost::ref.</p> <p>It supports arbitrary callables including member functions, function objects, and free functions, and all variations thereof. Anything that you can pass to the first argument of bind should be diagnosable. Currently, the only known case where a fix-it is unsupported is when the same placeholder is specified multiple times in the parameter list.</p> <p>Given:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> add(<span class="dt">int</span> x, <span class="dt">int</span> y) { <span class="kw">return</span> x + y; }</code></pre></div> <p>Then:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> f() { <span class="dt">int</span> x = <span class="dv">2</span>; <span class="kw">auto</span> clj = std::bind(add, x, _1); }</code></pre></div> <p>is replaced by:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> f() { <span class="dt">int</span> x = <span class="dv">2</span>; <span class="kw">auto</span> clj = [=](<span class="kw">auto</span> &amp;&amp; arg1) { <span class="kw">return</span> add(x, arg1); }; }</code></pre></div> <p>std::bind can be hard to read and can result in larger object files and binaries due to type information that will not be produced by equivalent lambdas.</p> <h5 id="options-65">Options</h5> <p>PermissiveParameterList</p> <p>If the option is set to true, the check will append auto&amp;&amp;... to the end of every placeholder parameter list. Without this, it is possible for a fix-it to perform an incorrect transformation in the case where the result of the bind is used in the context of a type erased functor such as std::function which allows mismatched arguments. For example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> add(<span class="dt">int</span> x, <span class="dt">int</span> y) { <span class="kw">return</span> x + y; } <span class="dt">int</span> foo() { std::function&lt;<span class="dt">int</span>(<span class="dt">int</span>,<span class="dt">int</span>)&gt; ignore_args = std::bind(add, <span class="dv">2</span>, <span class="dv">2</span>); <span class="kw">return</span> ignore_args(<span class="dv">3</span>, <span class="dv">3</span>); }</code></pre></div> <p>is valid code, and returns 4. The actual values passed to ignore_args are simply ignored. Without PermissiveParameterList, this would be transformed into</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> add(<span class="dt">int</span> x, <span class="dt">int</span> y) { <span class="kw">return</span> x + y; } <span class="dt">int</span> foo() { std::function&lt;<span class="dt">int</span>(<span class="dt">int</span>,<span class="dt">int</span>)&gt; ignore_args = [] { <span class="kw">return</span> add(<span class="dv">2</span>, <span class="dv">2</span>); } <span class="kw">return</span> ignore_args(<span class="dv">3</span>, <span class="dv">3</span>); }</code></pre></div> <p>which will <em>not</em> compile, since the lambda does not contain an operator() that that accepts 2 arguments. With permissive parameter list, it instead generates</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> add(<span class="dt">int</span> x, <span class="dt">int</span> y) { <span class="kw">return</span> x + y; } <span class="dt">int</span> foo() { std::function&lt;<span class="dt">int</span>(<span class="dt">int</span>,<span class="dt">int</span>)&gt; ignore_args = [](<span class="kw">auto</span>&amp;&amp;...) { <span class="kw">return</span> add(<span class="dv">2</span>, <span class="dv">2</span>); } <span class="kw">return</span> ignore_args(<span class="dv">3</span>, <span class="dv">3</span>); }</code></pre></div> <p>which is correct.</p> <p>This check requires using C++14 or higher to run.</p> <p>(Clang-Tidy original name: modernize-avoid-bind)</p> + + + + Major + + + + + + + true + false + modernize-avoid-c-arrays + modernize + + true + Avoid C Arrays + <p>cppcoreguidelines-avoid-c-arrays redirects here as an alias for this check.</p> <p>hicpp-avoid-c-arrays redirects here as an alias for this check.</p> <p>Finds C-style array types and recommend to use std::array&lt;&gt; / std::vector&lt;&gt;. All types of C arrays are diagnosed.</p> <p>However, fix-it are potentially dangerous in header files and are therefore not emitted right now.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> a[] = {<span class="dv">1</span>, <span class="dv">2</span>}; <span class="co">// warning: do not declare C-style arrays, use std::array&lt;&gt; instead</span> <span class="dt">int</span> b[<span class="dv">1</span>]; <span class="co">// warning: do not declare C-style arrays, use std::array&lt;&gt; instead</span> <span class="dt">void</span> foo() { <span class="dt">int</span> c[b[<span class="dv">0</span>]]; <span class="co">// warning: do not declare C VLA arrays, use std::vector&lt;&gt; instead</span> } <span class="kw">template</span> &lt;<span class="kw">typename</span> T, <span class="dt">int</span> Size&gt; <span class="kw">class</span> array { T d[Size]; <span class="co">// warning: do not declare C-style arrays, use std::array&lt;&gt; instead</span> <span class="dt">int</span> e[<span class="dv">1</span>]; <span class="co">// warning: do not declare C-style arrays, use std::array&lt;&gt; instead</span> }; array&lt;<span class="dt">int</span>[<span class="dv">4</span>], <span class="dv">2</span>&gt; d; <span class="co">// warning: do not declare C-style arrays, use std::array&lt;&gt; instead</span> <span class="kw">using</span> k = <span class="dt">int</span>[<span class="dv">4</span>]; <span class="co">// warning: do not declare C-style arrays, use std::array&lt;&gt; instead</span></code></pre></div> <p>However, the extern &quot;C&quot; code is ignored, since it is common to share such headers between C code, and C++ code.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Some header</span> <span class="dt">extern</span> <span class="st">&quot;C&quot;</span> { <span class="dt">int</span> f[] = {<span class="dv">1</span>, <span class="dv">2</span>}; <span class="co">// not diagnosed</span> <span class="dt">int</span> j[<span class="dv">1</span>]; <span class="co">// not diagnosed</span> <span class="kw">inline</span> <span class="dt">void</span> bar() { { <span class="dt">int</span> j[j[<span class="dv">0</span>]]; <span class="co">// not diagnosed</span> } } }</code></pre></div> <p>Similarly, the main() function is ignored. Its second and third parameters can be either char* argv[] or char** argv, but can not be std::array&lt;&gt;.</p> <p>(Clang-Tidy original name: modernize-avoid-c-arrays)</p> + + + + Major + + + + + + + true + false + modernize-concat-nested-namespaces + modernize + + true + Concat Nested Namespaces + <p>Checks for use of nested namespaces such as namespace a { namespace b { ... } } and suggests changing to the more concise syntax introduced in C++17: namespace a::b { ... }. Inline namespaces are not modified.</p> <p>For example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">namespace</span> n1 { <span class="kw">namespace</span> n2 { <span class="dt">void</span> t(); } } <span class="kw">namespace</span> n3 { <span class="kw">namespace</span> n4 { <span class="kw">namespace</span> n5 { <span class="dt">void</span> t(); } } <span class="kw">namespace</span> n6 { <span class="kw">namespace</span> n7 { <span class="dt">void</span> t(); } } }</code></pre></div> <p>Will be modified to:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">namespace</span> n1::n2 { <span class="dt">void</span> t(); } <span class="kw">namespace</span> n3 { <span class="kw">namespace</span> n4::n5 { <span class="dt">void</span> t(); } <span class="kw">namespace</span> n6::n7 { <span class="dt">void</span> t(); } }</code></pre></div> <p>(Clang-Tidy original name: modernize-concat-nested-namespaces)</p> + + + + Major + + + + + + + true + false + modernize-deprecated-headers + modernize + + true + Deprecated Headers + <p>Some headers from C library were deprecated in C++ and are no longer welcome in C++ codebases. Some have no effect in C++. For more details refer to the C++ 14 Standard [depr.c.headers] section.</p> <p>This check replaces C standard library headers with their C++ alternatives and removes redundant ones.</p> <p>Important note: the Standard doesn’t guarantee that the C++ headers declare all the same functions in the global namespace. The check in its current form can break the code that uses library symbols from the global namespace.</p> <ul> <li><assert.h></li> <li><complex.h></li> <li><ctype.h></li> <li><errno.h></li> <li><fenv.h> // deprecated since C++11</li> <li><float.h></li> <li><inttypes.h></li> <li><limits.h></li> <li><locale.h></li> <li><math.h></li> <li><setjmp.h></li> <li><signal.h></li> <li><stdarg.h></li> <li><stddef.h></li> <li><stdint.h></li> <li><stdio.h></li> <li><stdlib.h></li> <li><string.h></li> <li><tgmath.h> // deprecated since C++11</li> <li><time.h></li> <li><uchar.h> // deprecated since C++11</li> <li><wchar.h></li> <li><wctype.h></li> </ul> <p>If the specified standard is older than C++11 the check will only replace headers deprecated before C++11, otherwise – every header that appeared in the previous list.</p> <p>These headers don’t have effect in C++:</p> <ul> <li><iso646.h></li> <li><stdalign.h></li> <li><stdbool.h></li> </ul> <p>(Clang-Tidy original name: modernize-deprecated-headers)</p> + + + + Major + + + + + + + true + false + modernize-deprecated-ios-base-aliases + modernize + + true + Deprecated Ios Base Aliases + <p>Detects usage of the deprecated member types of std::ios_base and replaces those that have a non-deprecated equivalent.</p> <p>Deprecated member type | Replacement<br /> ---|---<br /> std::ios_base::io_state | std::ios_base::iostate<br /> std::ios_base::open_mode | std::ios_base::openmode<br /> std::ios_base::seek_dir | std::ios_base::seekdir<br /> std::ios_base::streamoff |<br /> std::ios_base::streampos |</p> <p>(Clang-Tidy original name: modernize-deprecated-ios-base-aliases)</p> + + + + Major + + + + + + + true + false + modernize-loop-convert + modernize + + true + Loop Convert + <p>This check converts for(...; ...; ...) loops to use the new range-based loops in C++11.</p> <p>Three kinds of loops can be converted:</p> <ul> <li>Loops over statically allocated arrays.</li> <li>Loops over containers, using iterators.</li> <li>Loops over array-like containers, using operator[] and at().</li> </ul> <h5 id="minconfidence-option">MinConfidence option</h5> <h6 id="risky">risky</h6> <p>In loops where the container expression is more complex than just a reference to a declared expression (a variable, function, enum, etc.), and some part of it appears elsewhere in the loop, we lower our confidence in the transformation due to the increased risk of changing semantics. Transformations for these loops are marked as risky, and thus will only be converted if the minimum required confidence level is set to risky.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> arr[<span class="dv">10</span>][<span class="dv">20</span>]; <span class="dt">int</span> l = <span class="dv">5</span>; <span class="kw">for</span> (<span class="dt">int</span> j = <span class="dv">0</span>; j &lt; <span class="dv">20</span>; ++j) <span class="dt">int</span> k = arr[l][j] + l; <span class="co">// using l outside arr[l] is considered risky</span> <span class="kw">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; obj.getVector().size(); ++i) obj.foo(<span class="dv">10</span>); <span class="co">// using &#39;obj&#39; is considered risky</span></code></pre></div> <p>See <a href="#incorrectriskytransformation">Range-based loops evaluate end() only once</a> for an example of an incorrect transformation when the minimum required confidence level is set to risky.</p> <h6 id="reasonable-default">reasonable (Default)</h6> <p>If a loop calls .end() or .size() after each iteration, the transformation for that loop is marked as reasonable, and thus will be converted if the required confidence level is set to reasonable (default) or lower.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// using size() is considered reasonable</span> <span class="kw">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; container.size(); ++i) cout &lt;&lt; container[i];</code></pre></div> <h6 id="safe">safe</h6> <p>Any other loops that do not match the above criteria to be marked as risky or reasonable are marked safe, and thus will be converted if the required confidence level is set to safe or lower.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> arr[] = {<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>}; <span class="kw">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; <span class="dv">3</span>; ++i) cout &lt;&lt; arr[i];</code></pre></div> <h5 id="example-8">Example</h5> <p>Original:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">const</span> <span class="dt">int</span> N = <span class="dv">5</span>; <span class="dt">int</span> arr[] = {<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>,<span class="dv">5</span>}; vector&lt;<span class="dt">int</span>&gt; v; v.push_back(<span class="dv">1</span>); v.push_back(<span class="dv">2</span>); v.push_back(<span class="dv">3</span>); <span class="co">// safe conversion</span> <span class="kw">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; N; ++i) cout &lt;&lt; arr[i]; <span class="co">// reasonable conversion</span> <span class="kw">for</span> (vector&lt;<span class="dt">int</span>&gt;::iterator it = v.begin(); it != v.end(); ++it) cout &lt;&lt; *it; <span class="co">// reasonable conversion</span> <span class="kw">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; v.size(); ++i) cout &lt;&lt; v[i];</code></pre></div> <p>After applying the check with minimum confidence level set to reasonable (default):</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">const</span> <span class="dt">int</span> N = <span class="dv">5</span>; <span class="dt">int</span> arr[] = {<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>,<span class="dv">5</span>}; vector&lt;<span class="dt">int</span>&gt; v; v.push_back(<span class="dv">1</span>); v.push_back(<span class="dv">2</span>); v.push_back(<span class="dv">3</span>); <span class="co">// safe conversion</span> <span class="kw">for</span> (<span class="kw">auto</span> &amp; elem : arr) cout &lt;&lt; elem; <span class="co">// reasonable conversion</span> <span class="kw">for</span> (<span class="kw">auto</span> &amp; elem : v) cout &lt;&lt; elem; <span class="co">// reasonable conversion</span> <span class="kw">for</span> (<span class="kw">auto</span> &amp; elem : v) cout &lt;&lt; elem;</code></pre></div> <h5 id="reverse-iterator-support">Reverse Iterator Support</h5> <p>The converter is also capable of transforming iterator loops which use rbegin and rend for looping backwards over a container. Out of the box this will automatically happen in C++20 mode using the ranges library, however the check can be configured to work without C++20 by specifying a function to reverse a range and optionally the header file where that function lives.</p> <p>UseCxx20ReverseRanges</p> <p>When set to true convert loops when in C++20 or later mode using std::ranges::reverse_view. Default value is true.</p> <p>MakeReverseRangeFunction</p> <p>Specify the function used to reverse an iterator pair, the function should accept a class with rbegin and rend methods and return a class with begin and end methods methods that call the rbegin and rend methods respectively. Common examples are ranges::reverse_view and llvm::reverse. Default value is an empty string.</p> <p>MakeReverseRangeHeader</p> <p>Specifies the header file where <a href="#cmdoption-arg-makereverserangefunction">MakeReverseRangeFunction</a> is declared. For the previous examples this option would be set to range/v3/view/reverse.hpp and llvm/ADT/STLExtras.h respectively. If this is an empty string and <a href="#cmdoption-arg-makereverserangefunction">MakeReverseRangeFunction</a> is set, the check will proceed on the assumption that the function is already available in the translation unit. This can be wrapped in angle brackets to signify to add the include as a system include. Default value is an empty string.</p> <p>IncludeStyle</p> <p>A string specifying which include-style is used, llvm or google. Default is llvm.</p> <h5 id="limitations-3">Limitations</h5> <p>There are certain situations where the tool may erroneously perform transformations that remove information and change semantics. Users of the tool should be aware of the behaviour and limitations of the check outlined by the cases below.</p> <h6 id="comments-inside-loop-headers">Comments inside loop headers</h6> <p>Comments inside the original loop header are ignored and deleted when transformed.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; N; <span class="co">/* This will be deleted */</span> ++i) { }</code></pre></div> <h6 id="range-based-loops-evaluate-end-only-once">Range-based loops evaluate end() only once</h6> <p>The C++11 range-based for loop calls .end() only once during the initialization of the loop. If in the original loop .end() is called after each iteration the semantics of the transformed loop may differ.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// The following is semantically equivalent to the C++11 range-based for loop,</span> <span class="co">// therefore the semantics of the header will not change.</span> <span class="kw">for</span> (iterator it = container.begin(), e = container.end(); it != e; ++it) { } <span class="co">// Instead of calling .end() after each iteration, this loop will be</span> <span class="co">// transformed to call .end() only once during the initialization of the loop,</span> <span class="co">// which may affect semantics.</span> <span class="kw">for</span> (iterator it = container.begin(); it != container.end(); ++it) { }</code></pre></div> <p>As explained above, calling member functions of the container in the body of the loop is considered risky. If the called member function modifies the container the semantics of the converted loop will differ due to .end() being called only once.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">bool</span> flag = <span class="kw">false</span>; <span class="kw">for</span> (vector&lt;T&gt;::iterator it = vec.begin(); it != vec.end(); ++it) { <span class="co">// Add a copy of the first element to the end of the vector.</span> <span class="kw">if</span> (!flag) { <span class="co">// This line makes this transformation &#39;risky&#39;.</span> vec.push_back(*it); flag = <span class="kw">true</span>; } cout &lt;&lt; *it; }</code></pre></div> <p>The original code above prints out the contents of the container including the newly added element while the converted loop, shown below, will only print the original contents and not the newly added element.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">bool</span> flag = <span class="kw">false</span>; <span class="kw">for</span> (<span class="kw">auto</span> &amp; elem : vec) { <span class="co">// Add a copy of the first element to the end of the vector.</span> <span class="kw">if</span> (!flag) { <span class="co">// This line makes this transformation &#39;risky&#39;</span> vec.push_back(elem); flag = <span class="kw">true</span>; } cout &lt;&lt; elem; }</code></pre></div> <p>Semantics will also be affected if .end() has side effects. For example, in the case where calls to .end() are logged the semantics will change in the transformed loop if .end() was originally called after each iteration.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">iterator end() { num_of_end_calls++; <span class="kw">return</span> container.end(); }</code></pre></div> <h6 id="overloaded-operator--with-side-effects">Overloaded operator-&gt;() with side effects</h6> <p>Similarly, if operator-&gt;() was overloaded to have side effects, such as logging, the semantics will change. If the iterator’s operator-&gt;() was used in the original loop it will be replaced with <container element>.<member> instead due to the implicit dereference as part of the range-based for loop. Therefore any side effect of the overloaded operator-&gt;() will no longer be performed.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">for</span> (iterator it = c.begin(); it != c.end(); ++it) { it-&gt;func(); <span class="co">// Using operator-&gt;()</span> } <span class="co">// Will be transformed to:</span> <span class="kw">for</span> (<span class="kw">auto</span> &amp; elem : c) { elem.func(); <span class="co">// No longer using operator-&gt;()</span> }</code></pre></div> <h6 id="pointers-and-references-to-containers">Pointers and references to containers</h6> <p>While most of the check’s risk analysis is dedicated to determining whether the iterator or container was modified within the loop, it is possible to circumvent the analysis by accessing and modifying the container through a pointer or reference.</p> <p>If the container were directly used instead of using the pointer or reference the following transformation would have only been applied at the risky level since calling a member function of the container is considered risky. The check cannot identify expressions associated with the container that are different than the one used in the loop header, therefore the transformation below ends up being performed at the safe level.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">vector&lt;<span class="dt">int</span>&gt; vec; vector&lt;<span class="dt">int</span>&gt; *ptr = &amp;vec; vector&lt;<span class="dt">int</span>&gt; &amp;ref = vec; <span class="kw">for</span> (vector&lt;<span class="dt">int</span>&gt;::iterator it = vec.begin(), e = vec.end(); it != e; ++it) { <span class="kw">if</span> (!flag) { <span class="co">// Accessing and modifying the container is considered risky, but the risk</span> <span class="co">// level is not raised here.</span> ptr-&gt;push_back(*it); ref.push_back(*it); flag = <span class="kw">true</span>; } }</code></pre></div> <h6 id="openmp">OpenMP</h6> <p>As range-based for loops are only available since OpenMP 5, this check should not been used on code with a compatibility requirements of OpenMP prior to version 5. It is <strong>intentional</strong> that this check does not make any attempts to exclude incorrect diagnostics on OpenMP for loops prior to OpenMP 5.</p> <p>To prevent this check to be applied (and to break) OpenMP for loops but still be applied to non-OpenMP for loops the usage of NOLINT (see <a href="../index.html#clang-tidy-nolint">Suppressing Undesired Diagnostics</a>) on the specific for loops is recommended.</p> <p>(Clang-Tidy original name: modernize-loop-convert)</p> + + + + Major + + + + + + + true + false + modernize-make-shared + modernize + + true + Make Shared + <p>This check finds the creation of std::shared_ptr objects by explicitly calling the constructor and a new expression, and replaces it with a call to std::make_shared.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">auto</span> my_ptr = std::shared_ptr&lt;MyPair&gt;(<span class="kw">new</span> MyPair(<span class="dv">1</span>, <span class="dv">2</span>)); <span class="co">// becomes</span> <span class="kw">auto</span> my_ptr = std::make_shared&lt;MyPair&gt;(<span class="dv">1</span>, <span class="dv">2</span>);</code></pre></div> <p>This check also finds calls to std::shared_ptr::reset() with a new expression, and replaces it with a call to std::make_shared.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">my_ptr.reset(<span class="kw">new</span> MyPair(<span class="dv">1</span>, <span class="dv">2</span>)); <span class="co">// becomes</span> my_ptr = std::make_shared&lt;MyPair&gt;(<span class="dv">1</span>, <span class="dv">2</span>);</code></pre></div> <h5 id="options-36">Options</h5> <p>MakeSmartPtrFunction</p> <p>A string specifying the name of make-shared-ptr function. Default is std::make_shared.</p> <p>MakeSmartPtrFunctionHeader</p> <p>A string specifying the corresponding header of make-shared-ptr function. Default is memory.</p> <p>IncludeStyle</p> <p>A string specifying which include-style is used, llvm or google. Default is llvm.</p> <p>IgnoreMacros</p> <p>If set to true, the check will not give warnings inside macros. Default is true.</p> <p>IgnoreDefaultInitialization</p> <p>If set to non-zero, the check does not suggest edits that will transform default initialization into value initialization, as this can cause performance regressions. Default is 1.</p> <p>(Clang-Tidy original name: modernize-make-shared)</p> + + + + Major + + + + + + + true + false + modernize-make-unique + modernize + + true + Make Unique + <p>This check finds the creation of std::unique_ptr objects by explicitly calling the constructor and a new expression, and replaces it with a call to std::make_unique, introduced in C++14.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">auto</span> my_ptr = std::unique_ptr&lt;MyPair&gt;(<span class="kw">new</span> MyPair(<span class="dv">1</span>, <span class="dv">2</span>)); <span class="co">// becomes</span> <span class="kw">auto</span> my_ptr = std::make_unique&lt;MyPair&gt;(<span class="dv">1</span>, <span class="dv">2</span>);</code></pre></div> <p>This check also finds calls to std::unique_ptr::reset() with a new expression, and replaces it with a call to std::make_unique.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">my_ptr.reset(<span class="kw">new</span> MyPair(<span class="dv">1</span>, <span class="dv">2</span>)); <span class="co">// becomes</span> my_ptr = std::make_unique&lt;MyPair&gt;(<span class="dv">1</span>, <span class="dv">2</span>);</code></pre></div> <h5 id="options-47">Options</h5> <p>MakeSmartPtrFunction</p> <p>A string specifying the name of make-unique-ptr function. Default is std::make_unique.</p> <p>MakeSmartPtrFunctionHeader</p> <p>A string specifying the corresponding header of make-unique-ptr function. Default is <memory>.</p> <p>IncludeStyle</p> <p>A string specifying which include-style is used, llvm or google. Default is llvm.</p> <p>IgnoreMacros</p> <p>If set to true, the check will not give warnings inside macros. Default is true.</p> <p>IgnoreDefaultInitialization</p> <p>If set to non-zero, the check does not suggest edits that will transform default initialization into value initialization, as this can cause performance regressions. Default is 1.</p> <p>(Clang-Tidy original name: modernize-make-unique)</p> + + + + Major + + + + + + + true + false + modernize-pass-by-value + modernize + + true + Pass By Value + <p>With move semantics added to the language and the standard library updated with move constructors added for many types it is now interesting to take an argument directly by value, instead of by const-reference, and then copy. This check allows the compiler to take care of choosing the best way to construct the copy.</p> <p>The transformation is usually beneficial when the calling code passes an <em>rvalue</em> and assumes the move construction is a cheap operation. This short example illustrates how the construction of the value happens:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo(std::string s); std::string get_str(); <span class="dt">void</span> f(<span class="dt">const</span> std::string &amp;str) { foo(str); <span class="co">// lvalue -&gt; copy construction</span> foo(get_str()); <span class="co">// prvalue -&gt; move construction</span> }</code></pre></div> <p>Note</p> <p>Currently, only constructors are transformed to make use of pass-by-value. Contributions that handle other situations are welcome!</p> <h5 id="pass-by-value-in-constructors">Pass-by-value in constructors</h5> <p>Replaces the uses of const-references constructor parameters that are copied into class fields. The parameter is then moved with std::move().</p> <p>Since std::move() is a library function declared in <utility> it may be necessary to add this include. The check will add the include directive when necessary.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"> <span class="ot">#include &lt;string&gt;</span> <span class="kw">class</span> Foo { <span class="kw">public</span>: - Foo(<span class="dt">const</span> std::string &amp;Copied, <span class="dt">const</span> std::string &amp;ReadOnly) - : Copied(Copied), ReadOnly(ReadOnly) + Foo(std::string Copied, <span class="dt">const</span> std::string &amp;ReadOnly) + : Copied(std::move(Copied)), ReadOnly(ReadOnly) {} <span class="kw">private</span>: std::string Copied; <span class="dt">const</span> std::string &amp;ReadOnly; }; std::string get_cwd(); <span class="dt">void</span> f(<span class="dt">const</span> std::string &amp;Path) { <span class="co">// The parameter corresponding to &#39;get_cwd()&#39; is move-constructed. By</span> <span class="co">// using pass-by-value in the Foo constructor we managed to avoid a</span> <span class="co">// copy-construction.</span> Foo foo(get_cwd(), Path); }</code></pre></div> <p>If the parameter is used more than once no transformation is performed since moved objects have an undefined state. It means the following code will be left untouched:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#include &lt;string&gt;</span> <span class="dt">void</span> pass(<span class="dt">const</span> std::string &amp;S); <span class="kw">struct</span> Foo { Foo(<span class="dt">const</span> std::string &amp;S) : Str(S) { pass(S); } std::string Str; };</code></pre></div> <h6 id="known-limitations">Known limitations</h6> <p>A situation where the generated code can be wrong is when the object referenced is modified before the assignment in the init-list through a “hidden” reference.</p> <p>Example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"> std::string s(<span class="st">&quot;foo&quot;</span>); <span class="kw">struct</span> Base { Base() { s = <span class="st">&quot;bar&quot;</span>; } }; <span class="kw">struct</span> Derived : Base { - Derived(<span class="dt">const</span> std::string &amp;S) : Field(S) + Derived(std::string S) : Field(std::move(S)) { } std::string Field; }; <span class="dt">void</span> f() { - Derived d(s); <span class="co">// d.Field holds &quot;bar&quot;</span> + Derived d(s); <span class="co">// d.Field holds &quot;foo&quot;</span> }</code></pre></div> <h6 id="note-about-delayed-template-parsing">Note about delayed template parsing</h6> <p>When delayed template parsing is enabled, constructors part of templated contexts; templated constructors, constructors in class templates, constructors of inner classes of template classes, etc., are not transformed. Delayed template parsing is enabled by default on Windows as a Microsoft extension: <a href="https://clang.llvm.org/docs/UsersManual.html#microsoft-extensions">Clang Compiler User’s Manual - Microsoft extensions</a>.</p> <p>Delayed template parsing can be enabled using the -fdelayed-template-parsing flag and disabled using -fno-delayed-template-parsing.</p> <p>Example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"> <span class="kw">template</span> &lt;<span class="kw">typename</span> T&gt; <span class="kw">class</span> C { std::string S; <span class="kw">public</span>: = <span class="co">// using -fdelayed-template-parsing (default on Windows)</span> = C(<span class="dt">const</span> std::string &amp;S) : S(S) {} + <span class="co">// using -fno-delayed-template-parsing (default on non-Windows systems)</span> + C(std::string S) : S(std::move(S)) {} };</code></pre></div> <p>See also</p> <p>For more information about the pass-by-value idiom, read: <a href="https://web.archive.org/web/20140205194657/http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/">Want Speed? Pass by Value</a>.</p> <h5 id="options-13">Options</h5> <p>IncludeStyle</p> <p>A string specifying which include-style is used, llvm or google. Default is llvm.</p> <p>ValuesOnly</p> <p>When true, the check only warns about copied parameters that are already passed by value. Default is false.</p> <p>(Clang-Tidy original name: modernize-pass-by-value)</p> + + + + Major + + + + + + + true + false + modernize-replace-auto-ptr + modernize + + true + Replace Auto Ptr + <p>This check replaces the uses of the deprecated class std::auto_ptr by std::unique_ptr (introduced in C++11). The transfer of ownership, done by the copy-constructor and the assignment operator, is changed to match std::unique_ptr usage by using explicit calls to std::move().</p> <p>Migration example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">-<span class="dt">void</span> take_ownership_fn(std::auto_ptr&lt;<span class="dt">int</span>&gt; int_ptr); +<span class="dt">void</span> take_ownership_fn(std::unique_ptr&lt;<span class="dt">int</span>&gt; int_ptr); <span class="dt">void</span> f(<span class="dt">int</span> x) { - std::auto_ptr&lt;<span class="dt">int</span>&gt; a(<span class="kw">new</span> <span class="dt">int</span>(x)); - std::auto_ptr&lt;<span class="dt">int</span>&gt; b; + std::unique_ptr&lt;<span class="dt">int</span>&gt; a(<span class="kw">new</span> <span class="dt">int</span>(x)); + std::unique_ptr&lt;<span class="dt">int</span>&gt; b; - b = a; - take_ownership_fn(b); + b = std::move(a); + take_ownership_fn(std::move(b)); }</code></pre></div> <p>Since std::move() is a library function declared in <utility> it may be necessary to add this include. The check will add the include directive when necessary.</p> <h5 id="known-limitations-5">Known Limitations</h5> <ul> <li>If headers modification is not activated or if a header is not allowed to be changed this check will produce broken code (compilation error), where the headers’ code will stay unchanged while the code using them will be changed.</li> <li>Client code that declares a reference to an std::auto_ptr coming from code that can’t be migrated (such as a header coming from a 3rd party library) will produce a compilation error after migration. This is because the type of the reference will be changed to std::unique_ptr but the type returned by the library won’t change, binding a reference to std::unique_ptr from an std::auto_ptr. This pattern doesn’t make much sense and usually std::auto_ptr are stored by value (otherwise what is the point in using them instead of a reference or a pointer?).</li> </ul> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"> <span class="co">// &lt;3rd-party header...&gt;</span> std::auto_ptr&lt;<span class="dt">int</span>&gt; get_value(); <span class="dt">const</span> std::auto_ptr&lt;<span class="dt">int</span>&gt; &amp; get_ref(); <span class="co">// &lt;calling code (with migration)...&gt;</span> -std::auto_ptr&lt;<span class="dt">int</span>&gt; a(get_value()); +std::unique_ptr&lt;<span class="dt">int</span>&gt; a(get_value()); <span class="co">// ok, unique_ptr constructed from auto_ptr</span> -<span class="dt">const</span> std::auto_ptr&lt;<span class="dt">int</span>&gt; &amp; p = get_ptr(); +<span class="dt">const</span> std::unique_ptr&lt;<span class="dt">int</span>&gt; &amp; p = get_ptr(); <span class="co">// won&#39;t compile</span></code></pre></div> <ul> <li>Non-instantiated templates aren’t modified.</li> </ul> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">template</span> &lt;<span class="kw">typename</span> X&gt; <span class="dt">void</span> f() { std::auto_ptr&lt;X&gt; p; } <span class="co">// only &#39;f&lt;int&gt;()&#39; (or similar) will trigger the replacement.</span></code></pre></div> <h5 id="options-69">Options</h5> <p>IncludeStyle</p> <p>A string specifying which include-style is used, llvm or google. Default is llvm.</p> <p>(Clang-Tidy original name: modernize-replace-auto-ptr)</p> + + + + Major + + + + + + + true + false + modernize-return-braced-init-list + modernize + + true + Return Braced Init List + <p>Replaces explicit calls to the constructor in a return with a braced initializer list. This way the return type is not needlessly duplicated in the function definition and the return statement.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">Foo bar() { Baz baz; <span class="kw">return</span> Foo(baz); } <span class="co">// transforms to:</span> Foo bar() { Baz baz; <span class="kw">return</span> {baz}; }</code></pre></div> <p>(Clang-Tidy original name: modernize-return-braced-init-list)</p> + + + + Major + + + + + + + true + false + modernize-replace-disallow-copy-and-assign-macro + modernize + + true + Replace Disallow Copy And Assign Macro + <p>Finds macro expansions of DISALLOW_COPY_AND_ASSIGN(Type) and replaces them with a deleted copy constructor and a deleted assignment operator.</p> <p>Before the delete keyword was introduced in C++11 it was common practice to declare a copy constructor and an assignment operator as a private members. This effectively makes them unusable to the public API of a class.</p> <p>With the advent of the delete keyword in C++11 we can abandon the private access of the copy constructor and the assignment operator and delete the methods entirely.</p> <p>When running this check on a code like this:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="kw">private</span>: DISALLOW_COPY_AND_ASSIGN(Foo); };</code></pre></div> <p>It will be transformed to this:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="kw">private</span>: Foo(<span class="dt">const</span> Foo &amp;) = <span class="kw">delete</span>; <span class="dt">const</span> Foo &amp;<span class="kw">operator</span>=(<span class="dt">const</span> Foo &amp;) = <span class="kw">delete</span>; };</code></pre></div> <h5 id="known-limitations-1">Known Limitations</h5> <ul> <li>Notice that the migration example above leaves the private access specification untouched. You might want to run the check <a href="modernize-use-equals-delete.html">modernize-use-equals-delete</a> to get warnings for deleted functions in private sections.</li> </ul> <h5 id="options-19">Options</h5> <p>MacroName</p> <p>A string specifying the macro name whose expansion will be replaced. Default is DISALLOW_COPY_AND_ASSIGN.</p> <p>See: <a href="https://en.cppreference.com/w/cpp/language/function\#Deleted_functions" class="uri">https://en.cppreference.com/w/cpp/language/function\#Deleted_functions</a></p> <p>(Clang-Tidy original name: modernize-replace-disallow-copy-and-assign-macro)</p> + + + + Major + + + + + + + true + false + modernize-replace-random-shuffle + modernize + + true + Replace Random Shuffle + <p>This check will find occurrences of std::random_shuffle and replace it with std::shuffle. In C++17 std::random_shuffle will no longer be available and thus we need to replace it.</p> <p>Below are two examples of what kind of occurrences will be found and two examples of what it will be replaced with.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::vector&lt;<span class="dt">int</span>&gt; v; <span class="co">// First example</span> std::random_shuffle(vec.begin(), vec.end()); <span class="co">// Second example</span> std::random_shuffle(vec.begin(), vec.end(), randomFunc);</code></pre></div> <p>Both of these examples will be replaced with:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::shuffle(vec.begin(), vec.end(), std::mt19937(std::random_device()()));</code></pre></div> <p>The second example will also receive a warning that randomFunc is no longer supported in the same way as before so if the user wants the same functionality, the user will need to change the implementation of the randomFunc.</p> <p>One thing to be aware of here is that std::random_device is quite expensive to initialize. So if you are using the code in a performance critical place, you probably want to initialize it elsewhere. Another thing is that the seeding quality of the suggested fix is quite poor: std::mt19937 has an internal state of 624 32-bit integers, but is only seeded with a single integer. So if you require higher quality randomness, you should consider seeding better, for example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::shuffle(v.begin(), v.end(), []() { std::mt19937::result_type seeds[std::mt19937::state_size]; std::random_device device; std::uniform_int_distribution&lt;<span class="kw">typename</span> std::mt19937::result_type&gt; dist; std::generate(std::begin(seeds), std::end(seeds), [&amp;] { <span class="kw">return</span> dist(device); }); std::seed_seq seq(std::begin(seeds), std::end(seeds)); <span class="kw">return</span> std::mt19937(seq); }());</code></pre></div> <p>(Clang-Tidy original name: modernize-replace-random-shuffle)</p> + + + + Major + + + + + + + true + false + modernize-raw-string-literal + modernize + + true + Raw String Literal + <p>This check selectively replaces string literals containing escaped characters with raw string literals.</p> <p>Example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">const</span> <span class="dt">char</span> *<span class="dt">const</span> Quotes{<span class="st">&quot;embedded </span><span class="ch">\&quot;</span><span class="st">quotes</span><span class="ch">\&quot;</span><span class="st">&quot;</span>}; <span class="dt">const</span> <span class="dt">char</span> *<span class="dt">const</span> Paragraph{<span class="st">&quot;Line one.</span><span class="ch">\n</span><span class="st">Line two.</span><span class="ch">\n</span><span class="st">Line three.</span><span class="ch">\n</span><span class="st">&quot;</span>}; <span class="dt">const</span> <span class="dt">char</span> *<span class="dt">const</span> SingleLine{<span class="st">&quot;Single line.</span><span class="ch">\n</span><span class="st">&quot;</span>}; <span class="dt">const</span> <span class="dt">char</span> *<span class="dt">const</span> TrailingSpace{<span class="st">&quot;Look here -&gt; </span><span class="ch">\n</span><span class="st">&quot;</span>}; <span class="dt">const</span> <span class="dt">char</span> *<span class="dt">const</span> Tab{<span class="st">&quot;One</span><span class="ch">\t</span><span class="st">Two</span><span class="ch">\n</span><span class="st">&quot;</span>}; <span class="dt">const</span> <span class="dt">char</span> *<span class="dt">const</span> Bell{<span class="st">&quot;Hello!</span><span class="ch">\a</span><span class="st"> And welcome!&quot;</span>}; <span class="dt">const</span> <span class="dt">char</span> *<span class="dt">const</span> Path{<span class="st">&quot;C:</span><span class="ch">\\</span><span class="st">Program Files</span><span class="ch">\\</span><span class="st">Vendor</span><span class="ch">\\</span><span class="st">Application.exe&quot;</span>}; <span class="dt">const</span> <span class="dt">char</span> *<span class="dt">const</span> RegEx{<span class="st">&quot;</span><span class="ch">\\</span><span class="st">w</span><span class="ch">\\</span><span class="st">([a-z]</span><span class="ch">\\</span><span class="st">)&quot;</span>};</code></pre></div> <p>becomes</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">const</span> <span class="dt">char</span> *<span class="dt">const</span> Quotes{<span class="st">R&quot;(embedded &quot;quotes&quot;)&quot;};</span> <span class="st">const char *const Paragraph{&quot;Line one.\nLine two.\nLine three.\n&quot;};</span> <span class="st">const char *const SingleLine{&quot;Single line.\n&quot;};</span> <span class="st">const char *const TrailingSpace{&quot;Look here -&gt; \n&quot;};</span> <span class="st">const char *const Tab{&quot;One\tTwo\n&quot;};</span> <span class="st">const char *const Bell{&quot;Hello!\a And welcome!&quot;};</span> <span class="st">const char *const Path{R&quot;(C:\Program Files\Vendor\Application.exe)&quot;};</span> <span class="st">const char *const RegEx{R&quot;(\w\([a-z]\))&quot;};</span></code></pre></div> <p>The presence of any of the following escapes can cause the string to be converted to a raw string literal: \, ', &quot;, ?, and octal or hexadecimal escapes for printable ASCII characters.</p> <p>A string literal containing only escaped newlines is a common way of writing lines of text output. Introducing physical newlines with raw string literals in this case is likely to impede readability. These string literals are left unchanged.</p> <p>An escaped horizontal tab, form feed, or vertical tab prevents the string literal from being converted. The presence of a horizontal tab, form feed or vertical tab in source code is not visually obvious.</p> <p>(Clang-Tidy original name: modernize-raw-string-literal)</p> + + + + Major + + + + + + + true + false + modernize-redundant-void-arg + modernize + + true + Redundant Void Arg + <p>Find and remove redundant void argument lists.</p> <p>Examples: Initial code | Code with applied fixes<br /> ---|---<br /> int f(void); | int f();<br /> int (<em>f(void))(void); | int (</em>f())();<br /> typedef int (<em>f_t(void))(void); | typedef int (</em>f_t())();<br /> void (C::<em>p)(void); | void (C::</em>p)();<br /> C::C(void) {} | C::C() {}<br /> C::~C(void) {} | C::~C() {}</p> <p>(Clang-Tidy original name: modernize-redundant-void-arg)</p> + + + + Major + + + + + + + true + false + modernize-shrink-to-fit + modernize + + true + Shrink To Fit + <p>Replace copy and swap tricks on shrinkable containers with the shrink_to_fit() method call.</p> <p>The shrink_to_fit() method is more readable and more effective than the copy and swap trick to reduce the capacity of a shrinkable container. Note that, the shrink_to_fit() method is only available in C++11 and up.</p> <p>(Clang-Tidy original name: modernize-shrink-to-fit)</p> + + + + Major + + + + + + + true + false + modernize-use-auto + modernize + + true + Use Auto + <p>This check is responsible for using the auto type specifier for variable declarations to <em>improve code readability and maintainability</em>. For example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::vector&lt;<span class="dt">int</span>&gt;::iterator I = my_container.begin(); <span class="co">// transforms to:</span> <span class="kw">auto</span> I = my_container.begin();</code></pre></div> <p>The auto type specifier will only be introduced in situations where the variable type matches the type of the initializer expression. In other words auto should deduce the same type that was originally spelled in the source. However, not every situation should be transformed:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> val = <span class="dv">42</span>; InfoStruct &amp;I = SomeObject.getInfo(); <span class="co">// Should not become:</span> <span class="kw">auto</span> val = <span class="dv">42</span>; <span class="kw">auto</span> &amp;I = SomeObject.getInfo();</code></pre></div> <p>In this example using auto for builtins doesn’t improve readability. In other situations it makes the code less self-documenting impairing readability and maintainability. As a result, auto is used only introduced in specific situations described below.</p> <h5 id="iterators">Iterators</h5> <p>Iterator type specifiers tend to be long and used frequently, especially in loop constructs. Since the functions generating iterators have a common format, the type specifier can be replaced without obscuring the meaning of code while improving readability and maintainability.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">for</span> (std::vector&lt;<span class="dt">int</span>&gt;::iterator I = my_container.begin(), E = my_container.end(); I != E; ++I) { } <span class="co">// becomes</span> <span class="kw">for</span> (<span class="kw">auto</span> I = my_container.begin(), E = my_container.end(); I != E; ++I) { }</code></pre></div> <p>The check will only replace iterator type-specifiers when all of the following conditions are satisfied:</p> <ul> <li>The iterator is for one of the standard container in std namespace: <ul> <li>array</li> <li>deque</li> <li>forward_list</li> <li>list</li> <li>vector</li> <li>map</li> <li>multimap</li> <li>set</li> <li>multiset</li> <li>unordered_map</li> <li>unordered_multimap</li> <li>unordered_set</li> <li>unordered_multiset</li> <li>queue</li> <li>priority_queue</li> <li>stack</li> </ul></li> <li>The iterator is one of the possible iterator types for standard containers: <ul> <li>iterator</li> <li>reverse_iterator</li> <li>const_iterator</li> <li>const_reverse_iterator</li> </ul></li> <li>In addition to using iterator types directly, typedefs or other ways of referring to those types are also allowed. However, implementation-specific types for which a type like std::vector<int>::iterator is itself a typedef will not be transformed. Consider the following examples:</li> </ul> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// The following direct uses of iterator types will be transformed.</span> std::vector&lt;<span class="dt">int</span>&gt;::iterator I = MyVec.begin(); { <span class="kw">using</span> <span class="kw">namespace</span> std; list&lt;<span class="dt">int</span>&gt;::iterator I = MyList.begin(); } <span class="co">// The type specifier for J would transform to auto since it&#39;s a typedef</span> <span class="co">// to a standard iterator type.</span> <span class="kw">typedef</span> std::map&lt;<span class="dt">int</span>, std::string&gt;::const_iterator map_iterator; map_iterator J = MyMap.begin(); <span class="co">// The following implementation-specific iterator type for which</span> <span class="co">// std::vector&lt;int&gt;::iterator could be a typedef would not be transformed.</span> __gnu_cxx::__normal_iterator&lt;<span class="dt">int</span>*, std::vector&gt; K = MyVec.begin();</code></pre></div> <ul> <li>The initializer for the variable being declared is not a braced initializer list. Otherwise, use of auto would cause the type of the variable to be deduced as std::initializer_list.</li> </ul> <h5 id="new-expressions">New expressions</h5> <p>Frequently, when a pointer is declared and initialized with new, the pointee type is written twice: in the declaration type and in the new expression. In this cases, the declaration type can be replaced with auto improving readability and maintainability.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">TypeName *my_pointer = <span class="kw">new</span> TypeName(my_param); <span class="co">// becomes</span> <span class="kw">auto</span> *my_pointer = <span class="kw">new</span> TypeName(my_param);</code></pre></div> <p>The check will also replace the declaration type in multiple declarations, if the following conditions are satisfied:</p> <ul> <li>All declared variables have the same type (i.e. all of them are pointers to the same type).</li> <li>All declared variables are initialized with a new expression.</li> <li>The types of all the new expressions are the same than the pointee of the declaration type.</li> </ul> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">TypeName *my_first_pointer = <span class="kw">new</span> TypeName, *my_second_pointer = <span class="kw">new</span> TypeName; <span class="co">// becomes</span> <span class="kw">auto</span> *my_first_pointer = <span class="kw">new</span> TypeName, *my_second_pointer = <span class="kw">new</span> TypeName;</code></pre></div> <h5 id="cast-expressions">Cast expressions</h5> <p>Frequently, when a variable is declared and initialized with a cast, the variable type is written twice: in the declaration type and in the cast expression. In this cases, the declaration type can be replaced with auto improving readability and maintainability.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">TypeName *my_pointer = <span class="kw">static_cast</span>&lt;TypeName&gt;(my_param); <span class="co">// becomes</span> <span class="kw">auto</span> *my_pointer = <span class="kw">static_cast</span>&lt;TypeName&gt;(my_param);</code></pre></div> <p>The check handles static_cast, dynamic_cast, const_cast, reinterpret_cast, functional casts, C-style casts and function templates that behave as casts, such as llvm::dyn_cast, boost::lexical_cast and gsl::narrow_cast. Calls to function templates are considered to behave as casts if the first template argument is explicit and is a type, and the function returns that type, or a pointer or reference to it.</p> <h5 id="known-limitations-2">Known Limitations</h5> <ul> <li>If the initializer is an explicit conversion constructor, the check will not replace the type specifier even though it would be safe to do so.</li> <li>User-defined iterators are not handled at this time.</li> </ul> <h5 id="options-21">Options</h5> <p>MinTypeNameLength</p> <p>If the option is set to non-zero (default 5), the check will ignore type names having a length less than the option value. The option affects expressions only, not iterators. Spaces between multi-lexeme type names (long int) are considered as one. If the <a href="#cmdoption-arg-removestars">RemoveStars</a> option (see below) is set to true, then *s in the type are also counted as a part of the type name.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// MinTypeNameLength = 0, RemoveStars=0</span> <span class="dt">int</span> a = <span class="kw">static_cast</span>&lt;<span class="dt">int</span>&gt;(foo()); <span class="co">// ---&gt; auto a = ...</span> <span class="co">// length(bool *) = 4</span> <span class="dt">bool</span> *b = <span class="kw">new</span> <span class="dt">bool</span>; <span class="co">// ---&gt; auto *b = ...</span> <span class="dt">unsigned</span> c = <span class="kw">static_cast</span>&lt;<span class="dt">unsigned</span>&gt;(foo()); <span class="co">// ---&gt; auto c = ...</span> <span class="co">// MinTypeNameLength = 5, RemoveStars=0</span> <span class="dt">int</span> a = <span class="kw">static_cast</span>&lt;<span class="dt">int</span>&gt;(foo()); <span class="co">// ---&gt; int a = ...</span> <span class="dt">bool</span> b = <span class="kw">static_cast</span>&lt;<span class="dt">bool</span>&gt;(foo()); <span class="co">// ---&gt; bool b = ...</span> <span class="dt">bool</span> *pb = <span class="kw">static_cast</span>&lt;<span class="dt">bool</span>*&gt;(foo()); <span class="co">// ---&gt; bool *pb = ...</span> <span class="dt">unsigned</span> c = <span class="kw">static_cast</span>&lt;<span class="dt">unsigned</span>&gt;(foo()); <span class="co">// ---&gt; auto c = ...</span> <span class="co">// length(long &lt;on-or-more-spaces&gt; int) = 8</span> <span class="dt">long</span> <span class="dt">int</span> d = <span class="kw">static_cast</span>&lt;<span class="dt">long</span> <span class="dt">int</span>&gt;(foo()); <span class="co">// ---&gt; auto d = ...</span> <span class="co">// MinTypeNameLength = 5, RemoveStars=1</span> <span class="dt">int</span> a = <span class="kw">static_cast</span>&lt;<span class="dt">int</span>&gt;(foo()); <span class="co">// ---&gt; int a = ...</span> <span class="co">// length(int * * ) = 5</span> <span class="dt">int</span> **pa = <span class="kw">static_cast</span>&lt;<span class="dt">int</span>**&gt;(foo()); <span class="co">// ---&gt; auto pa = ...</span> <span class="dt">bool</span> b = <span class="kw">static_cast</span>&lt;<span class="dt">bool</span>&gt;(foo()); <span class="co">// ---&gt; bool b = ...</span> <span class="dt">bool</span> *pb = <span class="kw">static_cast</span>&lt;<span class="dt">bool</span>*&gt;(foo()); <span class="co">// ---&gt; auto pb = ...</span> <span class="dt">unsigned</span> c = <span class="kw">static_cast</span>&lt;<span class="dt">unsigned</span>&gt;(foo()); <span class="co">// ---&gt; auto c = ...</span> <span class="dt">long</span> <span class="dt">int</span> d = <span class="kw">static_cast</span>&lt;<span class="dt">long</span> <span class="dt">int</span>&gt;(foo()); <span class="co">// ---&gt; auto d = ...</span></code></pre></div> <p>RemoveStars</p> <p>If the option is set to true (default is false), the check will remove stars from the non-typedef pointer types when replacing type names with auto. Otherwise, the check will leave stars. For example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">TypeName *my_first_pointer = <span class="kw">new</span> TypeName, *my_second_pointer = <span class="kw">new</span> TypeName; <span class="co">// RemoveStars = 0</span> <span class="kw">auto</span> *my_first_pointer = <span class="kw">new</span> TypeName, *my_second_pointer = <span class="kw">new</span> TypeName; <span class="co">// RemoveStars = 1</span> <span class="kw">auto</span> my_first_pointer = <span class="kw">new</span> TypeName, my_second_pointer = <span class="kw">new</span> TypeName;</code></pre></div> <p>(Clang-Tidy original name: modernize-use-auto)</p> + + + + Major + + + + + + + true + false + modernize-use-bool-literals + modernize + + true + Use Bool Literals + <p>Finds integer literals which are cast to bool.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">bool</span> p = <span class="dv">1</span>; <span class="dt">bool</span> f = <span class="kw">static_cast</span>&lt;<span class="dt">bool</span>&gt;(<span class="dv">1</span>); std::ios_base::sync_with_stdio(<span class="dv">0</span>); <span class="dt">bool</span> x = p ? <span class="dv">1</span> : <span class="dv">0</span>; <span class="co">// transforms to</span> <span class="dt">bool</span> p = <span class="kw">true</span>; <span class="dt">bool</span> f = <span class="kw">true</span>; std::ios_base::sync_with_stdio(<span class="kw">false</span>); <span class="dt">bool</span> x = p ? <span class="kw">true</span> : <span class="kw">false</span>;</code></pre></div> <h5 id="options-5">Options</h5> <p>IgnoreMacros</p> <p>If set to true, the check will not give warnings inside macros. Default is true.</p> <p>(Clang-Tidy original name: modernize-use-bool-literals)</p> + + + + Major + + + + + + + true + false + modernize-use-default-member-init + modernize + + true + Use Default Member Init + <p>This check converts a default constructor’s member initializers into the new default member initializers in C++11. Other member initializers that match the default member initializer are removed. This can reduce repeated code or allow use of ‘= default’.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> A { A() : i(<span class="dv">5</span>), j(<span class="fl">10.0</span>) {} A(<span class="dt">int</span> i) : i(i), j(<span class="fl">10.0</span>) {} <span class="dt">int</span> i; <span class="dt">double</span> j; }; <span class="co">// becomes</span> <span class="kw">struct</span> A { A() {} A(<span class="dt">int</span> i) : i(i) {} <span class="dt">int</span> i{<span class="dv">5</span>}; <span class="dt">double</span> j{<span class="fl">10.0</span>}; };</code></pre></div> <p>Note</p> <p>Only converts member initializers for built-in types, enums, and pointers. The readability-redundant-member-init check will remove redundant member initializers for classes.</p> <h5 id="options-25">Options</h5> <p>UseAssignment</p> <p>If this option is set to true (default is false), the check will initialise members with an assignment. For example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> A { A() {} A(<span class="dt">int</span> i) : i(i) {} <span class="dt">int</span> i = <span class="dv">5</span>; <span class="dt">double</span> j = <span class="fl">10.0</span>; };</code></pre></div> <p>IgnoreMacros</p> <p>If this option is set to true (default is true), the check will not warn about members declared inside macros.</p> <p>(Clang-Tidy original name: modernize-use-default-member-init)</p> + + + + Major + + + + + + + true + false + modernize-use-emplace + modernize + + true + Use Emplace + <p>The check flags insertions to an STL-style container done by calling the push_back method with an explicitly-constructed temporary of the container element type. In this case, the corresponding emplace_back method results in less verbose and potentially more efficient code. Right now the check doesn’t support push_front and insert. It also doesn’t support insert functions for associative containers because replacing insert with emplace may result in <a href="https://htmlpreview.github.io/?https://github.com/HowardHinnant/papers/blob/master/insert_vs_emplace.html">speed regression</a>, but it might get support with some addition flag in the future.</p> <p>By default only std::vector, std::deque, std::list are considered. This list can be modified using the <a href="#cmdoption-arg-containerswithpushback">ContainersWithPushBack</a> option.</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::vector&lt;MyClass&gt; v; v.push_back(MyClass(<span class="dv">21</span>, <span class="dv">37</span>)); std::vector&lt;std::pair&lt;<span class="dt">int</span>, <span class="dt">int</span>&gt;&gt; w; w.push_back(std::pair&lt;<span class="dt">int</span>, <span class="dt">int</span>&gt;(<span class="dv">21</span>, <span class="dv">37</span>)); w.push_back(std::make_pair(<span class="dv">21L</span>, <span class="dv">37L</span>));</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::vector&lt;MyClass&gt; v; v.emplace_back(<span class="dv">21</span>, <span class="dv">37</span>); std::vector&lt;std::pair&lt;<span class="dt">int</span>, <span class="dt">int</span>&gt;&gt; w; w.emplace_back(<span class="dv">21</span>, <span class="dv">37</span>); w.emplace_back(<span class="dv">21L</span>, <span class="dv">37L</span>);</code></pre></div> <p>By default, the check is able to remove unnecessary std::make_pair and std::make_tuple calls from push_back calls on containers of std::pair and std::tuple. Custom tuple-like types can be modified by the <a href="#cmdoption-arg-tupletypes">TupleTypes</a> option; custom make functions can be modified by the <a href="#cmdoption-arg-tuplemakefunctions">TupleMakeFunctions</a> option.</p> <p>The other situation is when we pass arguments that will be converted to a type inside a container.</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::vector&lt;boost::optional&lt;std::string&gt; &gt; v; v.push_back(<span class="st">&quot;abc&quot;</span>);</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::vector&lt;boost::optional&lt;std::string&gt; &gt; v; v.emplace_back(<span class="st">&quot;abc&quot;</span>);</code></pre></div> <p>In some cases the transformation would be valid, but the code wouldn’t be exception safe. In this case the calls of push_back won’t be replaced.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::vector&lt;std::unique_ptr&lt;<span class="dt">int</span>&gt;&gt; v; v.push_back(std::unique_ptr&lt;<span class="dt">int</span>&gt;(<span class="kw">new</span> <span class="dt">int</span>(<span class="dv">0</span>))); <span class="kw">auto</span> *ptr = <span class="kw">new</span> <span class="dt">int</span>(<span class="dv">1</span>); v.push_back(std::unique_ptr&lt;<span class="dt">int</span>&gt;(ptr));</code></pre></div> <p>This is because replacing it with emplace_back could cause a leak of this pointer if emplace_back would throw exception before emplacement (e.g. not enough memory to add a new element).</p> <p>For more info read item 42 - “Consider emplacement instead of insertion.” of Scott Meyers “Effective Modern C++”.</p> <p>The default smart pointers that are considered are std::unique_ptr, std::shared_ptr, std::auto_ptr. To specify other smart pointers or other classes use the <a href="#cmdoption-arg-smartpointers">SmartPointers</a> option.</p> <p>Check also doesn’t fire if any argument of the constructor call would be:</p> <ul> <li>a bit-field (bit-fields can’t bind to rvalue/universal reference)</li> <li>a new expression (to avoid leak)</li> <li>if the argument would be converted via derived-to-base cast.</li> </ul> <p>This check requires C++11 or higher to run.</p> <h5 id="options">Options</h5> <p>ContainersWithPushBack</p> <p>Semicolon-separated list of class names of custom containers that support push_back.</p> <p>IgnoreImplicitConstructors</p> <p>When true, the check will ignore implicitly constructed arguments of push_back, e.g.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::vector&lt;std::string&gt; v; v.push_back(<span class="st">&quot;a&quot;</span>); <span class="co">// Ignored when IgnoreImplicitConstructors is `true`.</span></code></pre></div> <p>Default is false.</p> <p>SmartPointers</p> <p>Semicolon-separated list of class names of custom smart pointers.</p> <p>TupleTypes</p> <p>Semicolon-separated list of std::tuple-like class names.</p> <p>TupleMakeFunctions</p> <p>Semicolon-separated list of std::make_tuple-like function names. Those function calls will be removed from push_back calls and turned into emplace_back.</p> <h6 id="example">Example</h6> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::vector&lt;MyTuple&lt;<span class="dt">int</span>, <span class="dt">bool</span>, <span class="dt">char</span>&gt;&gt; x; x.push_back(MakeMyTuple(<span class="dv">1</span>, <span class="kw">false</span>, <span class="st">&#39;x&#39;</span>));</code></pre></div> <p>transforms to:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::vector&lt;MyTuple&lt;<span class="dt">int</span>, <span class="dt">bool</span>, <span class="dt">char</span>&gt;&gt; x; x.emplace_back(<span class="dv">1</span>, <span class="kw">false</span>, <span class="st">&#39;x&#39;</span>);</code></pre></div> <p>when <a href="#cmdoption-arg-tupletypes">TupleTypes</a> is set to MyTuple and <a href="#cmdoption-arg-tuplemakefunctions">TupleMakeFunctions</a> is set to MakeMyTuple.</p> <p>(Clang-Tidy original name: modernize-use-emplace)</p> + + + + Major + + + + + + + true + false + modernize-use-equals-default + modernize + + true + Use Equals Default + <p>This check replaces default bodies of special member functions with = default;. The explicitly defaulted function declarations enable more opportunities in optimization, because the compiler might treat explicitly defaulted functions as trivial.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> A { A() {} ~A(); }; A::~A() {} <span class="co">// becomes</span> <span class="kw">struct</span> A { A() = <span class="kw">default</span>; ~A(); }; A::~A() = <span class="kw">default</span>;</code></pre></div> <p>Note</p> <p>Move-constructor and move-assignment operator are not supported yet.</p> <h5 id="options-26">Options</h5> <p>IgnoreMacros</p> <p>If set to true, the check will not give warnings inside macros. Default is true.</p> <p>(Clang-Tidy original name: modernize-use-equals-default)</p> + + + + Major + + + + + + + true + false + modernize-use-equals-delete + modernize + + true + Use Equals Delete + <p>This check marks unimplemented private special member functions with = delete. To avoid false-positives, this check only applies in a translation unit that has all other member functions implemented.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> A { <span class="kw">private</span>: A(<span class="dt">const</span> A&amp;); A&amp; <span class="kw">operator</span>=(<span class="dt">const</span> A&amp;); }; <span class="co">// becomes</span> <span class="kw">struct</span> A { <span class="kw">private</span>: A(<span class="dt">const</span> A&amp;) = <span class="kw">delete</span>; A&amp; <span class="kw">operator</span>=(<span class="dt">const</span> A&amp;) = <span class="kw">delete</span>; };</code></pre></div> <p>IgnoreMacros</p> <p>If this option is set to true (default is true), the check will not warn about functions declared inside macros.</p> <p>(Clang-Tidy original name: modernize-use-equals-delete)</p> + + + + Major + + + + + + + true + false + modernize-use-nodiscard + modernize + + true + Use Nodiscard + <p>Adds [[nodiscard]] attributes (introduced in C++17) to member functions in order to highlight at compile time which return values should not be ignored.</p> <p>Member functions need to satisfy the following conditions to be considered by this check:</p> <ul> <li>no [[nodiscard]], [[noreturn]], <strong>attribute</strong>((warn_unused_result)), [[clang::warn_unused_result]] nor [[gcc::warn_unused_result]] attribute,</li> <li>non-void return type,</li> <li>non-template return types,</li> <li>const member function,</li> <li>non-variadic functions,</li> <li>no non-const reference parameters,</li> <li>no pointer parameters,</li> <li>no template parameters,</li> <li>no template function parameters,</li> <li>not be a member of a class with mutable member variables,</li> <li>no Lambdas,</li> <li>no conversion functions.</li> </ul> <p>Such functions have no means of altering any state or passing values other than via the return type. Unless the member functions are altering state via some external call (e.g. I/O).</p> <h5 id="example-6">Example</h5> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">bool</span> empty() <span class="dt">const</span>; <span class="dt">bool</span> empty(<span class="dt">int</span> i) <span class="dt">const</span>;</code></pre></div> <p>transforms to:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">[[<span class="kw">nodiscard</span>] <span class="kw">bool</span> <span class="kw">empty</span>() <span class="kw">const</span>; [[<span class="kw">nodiscard</span>] <span class="kw">bool</span> <span class="kw">empty</span>(<span class="kw">int</span> <span class="kw">i</span>) <span class="kw">const</span>;</code></pre></div> <h5 id="options-60">Options</h5> <p>ReplacementString</p> <p>Specifies a macro to use instead of [[nodiscard]]. This is useful when maintaining source code that needs to compile with a pre-C++17 compiler.</p> <h6 id="example-7">Example</h6> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">bool</span> empty() <span class="dt">const</span>; <span class="dt">bool</span> empty(<span class="dt">int</span> i) <span class="dt">const</span>;</code></pre></div> <p>transforms to:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">NO_DISCARD <span class="dt">bool</span> empty() <span class="dt">const</span>; NO_DISCARD <span class="dt">bool</span> empty(<span class="dt">int</span> i) <span class="dt">const</span>;</code></pre></div> <p>if the <a href="modernize-use-noexcept.html#cmdoption-arg-replacementstring">ReplacementString</a> option is set to NO_DISCARD.</p> <p>Note</p> <p>If the <a href="modernize-use-noexcept.html#cmdoption-arg-replacementstring">ReplacementString</a> is not a C++ attribute, but instead a macro, then that macro must be defined in scope or the fix-it will not be applied.</p> <p>Note</p> <p>For alternative <strong>attribute</strong> syntax options to mark functions as [[nodiscard]] in non-c++17 source code. See <a href="https://clang.llvm.org/docs/AttributeReference.html\#nodiscard-warn-unused-result" class="uri">https://clang.llvm.org/docs/AttributeReference.html\#nodiscard-warn-unused-result</a></p> <p>(Clang-Tidy original name: modernize-use-nodiscard)</p> + + + + Major + + + + + + + true + false + modernize-use-noexcept + modernize + + true + Use Noexcept + <p>This check replaces deprecated dynamic exception specifications with the appropriate noexcept specification (introduced in C++11). By default this check will replace throw() with noexcept, and throw(<exception>[,...]) or throw(...) with noexcept(false).</p> <h5 id="example-13">Example</h5> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo() <span class="kw">throw</span>(); <span class="dt">void</span> bar() <span class="kw">throw</span>(<span class="dt">int</span>) {}</code></pre></div> <p>transforms to:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo() <span class="kw">noexcept</span>; <span class="dt">void</span> bar() <span class="kw">noexcept</span>(<span class="kw">false</span>) {}</code></pre></div> <h5 id="options-83">Options</h5> <p>ReplacementString</p> <p>Users can use <a href="#cmdoption-arg-replacementstring">ReplacementString</a> to specify a macro to use instead of noexcept. This is useful when maintaining source code that uses custom exception specification marking other than noexcept. Fix-it hints will only be generated for non-throwing specifications.</p> <h6 id="example-14">Example</h6> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> bar() <span class="kw">throw</span>(<span class="dt">int</span>); <span class="dt">void</span> foo() <span class="kw">throw</span>();</code></pre></div> <p>transforms to:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> bar() <span class="kw">throw</span>(<span class="dt">int</span>); <span class="co">// No fix-it generated.</span> <span class="dt">void</span> foo() NOEXCEPT;</code></pre></div> <p>if the <a href="#cmdoption-arg-replacementstring">ReplacementString</a> option is set to NOEXCEPT.</p> <p>UseNoexceptFalse</p> <p>Enabled by default, disabling will generate fix-it hints that remove throwing dynamic exception specs, e.g., throw(<something>), completely without providing a replacement text, except for destructors and delete operators that are noexcept(true) by default.</p> <h6 id="example-15">Example</h6> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo() <span class="kw">throw</span>(<span class="dt">int</span>) {} <span class="kw">struct</span> bar { <span class="dt">void</span> foobar() <span class="kw">throw</span>(<span class="dt">int</span>); <span class="dt">void</span> <span class="kw">operator</span> <span class="kw">delete</span>(<span class="dt">void</span> *ptr) <span class="kw">throw</span>(<span class="dt">int</span>); <span class="dt">void</span> <span class="kw">operator</span> <span class="kw">delete</span>[](<span class="dt">void</span> *ptr) <span class="kw">throw</span>(<span class="dt">int</span>); ~bar() <span class="kw">throw</span>(<span class="dt">int</span>); }</code></pre></div> <p>transforms to:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo() {} <span class="kw">struct</span> bar { <span class="dt">void</span> foobar(); <span class="dt">void</span> <span class="kw">operator</span> <span class="kw">delete</span>(<span class="dt">void</span> *ptr) <span class="kw">noexcept</span>(<span class="kw">false</span>); <span class="dt">void</span> <span class="kw">operator</span> <span class="kw">delete</span>[](<span class="dt">void</span> *ptr) <span class="kw">noexcept</span>(<span class="kw">false</span>); ~bar() <span class="kw">noexcept</span>(<span class="kw">false</span>); }</code></pre></div> <p>if the <a href="#cmdoption-arg-usenoexceptfalse">UseNoexceptFalse</a> option is set to false.</p> <p>(Clang-Tidy original name: modernize-use-noexcept)</p> + + + + Major + + + + + + + true + false + modernize-use-nullptr + modernize + + true + Use Nullptr + <p>The check converts the usage of null pointer constants (eg. NULL, 0) to use the new C++11 nullptr keyword.</p> <h5 id="example-11">Example</h5> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> assignment() { <span class="dt">char</span> *a = NULL; <span class="dt">char</span> *b = <span class="dv">0</span>; <span class="dt">char</span> c = <span class="dv">0</span>; } <span class="dt">int</span> *ret_ptr() { <span class="kw">return</span> <span class="dv">0</span>; }</code></pre></div> <p>transforms to:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> assignment() { <span class="dt">char</span> *a = <span class="kw">nullptr</span>; <span class="dt">char</span> *b = <span class="kw">nullptr</span>; <span class="dt">char</span> c = <span class="dv">0</span>; } <span class="dt">int</span> *ret_ptr() { <span class="kw">return</span> <span class="kw">nullptr</span>; }</code></pre></div> <h5 id="options-82">Options</h5> <p>NullMacros</p> <p>Comma-separated list of macro names that will be transformed along with NULL. By default this check will only replace the NULL macro and will skip any similar user-defined macros.</p> <h6 id="example-12">Example</h6> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#define MY_NULL (void*)0</span> <span class="dt">void</span> assignment() { <span class="dt">void</span> *p = MY_NULL; }</code></pre></div> <p>transforms to:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#define MY_NULL NULL</span> <span class="dt">void</span> assignment() { <span class="dt">int</span> *p = <span class="kw">nullptr</span>; }</code></pre></div> <p>if the <a href="#cmdoption-arg-nullmacros">NullMacros</a> option is set to MY_NULL.</p> <p>(Clang-Tidy original name: modernize-use-nullptr)</p> + + + + Major + + + + + + + true + false + modernize-use-override + modernize + + true + Use Override + <p>Adds override (introduced in C++11) to overridden virtual functions and removes virtual from those functions as it is not required.</p> <p>virtual on non base class implementations was used to help indicate to the user that a function was virtual. C++ compilers did not use the presence of this to signify an overridden function.</p> <p>In C++ 11 override and final keywords were introduced to allow overridden functions to be marked appropriately. Their presence allows compilers to verify that an overridden function correctly overrides a base class implementation.</p> <p>This can be useful as compilers can generate a compile time error when:</p> <ul> <li>The base class implementation function signature changes.</li> <li>The user has not created the override with the correct signature.</li> </ul> <h5 id="options-56">Options</h5> <p>IgnoreDestructors</p> <p>If set to true, this check will not diagnose destructors. Default is false.</p> <p>AllowOverrideAndFinal</p> <p>If set to true, this check will not diagnose override as redundant with final. This is useful when code will be compiled by a compiler with warning/error checking flags requiring override explicitly on overridden members, such as gcc -Wsuggest-override/gcc -Werror=suggest-override. Default is false.</p> <p>OverrideSpelling</p> <p>Specifies a macro to use instead of override. This is useful when maintaining source code that also needs to compile with a pre-C++11 compiler.</p> <p>FinalSpelling</p> <p>Specifies a macro to use instead of final. This is useful when maintaining source code that also needs to compile with a pre-C++11 compiler.</p> <p>Note</p> <p>For more information on the use of override see <a href="https://en.cppreference.com/w/cpp/language/override" class="uri">https://en.cppreference.com/w/cpp/language/override</a></p> <p>(Clang-Tidy original name: modernize-use-override)</p> + + + + Major + + + + + + + true + false + modernize-unary-static-assert + modernize + + true + Unary Static Assert + <p>The check diagnoses any static_assert declaration with an empty string literal and provides a fix-it to replace the declaration with a single-argument static_assert declaration.</p> <p>The check is only applicable for C++17 and later code.</p> <p>The following code:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> f_textless(<span class="dt">int</span> a) { <span class="kw">static_assert</span>(<span class="kw">sizeof</span>(a) &lt;= <span class="dv">10</span>, <span class="st">&quot;&quot;</span>); }</code></pre></div> <p>is replaced by:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> f_textless(<span class="dt">int</span> a) { <span class="kw">static_assert</span>(<span class="kw">sizeof</span>(a) &lt;= <span class="dv">10</span>); }</code></pre></div> <p>(Clang-Tidy original name: modernize-unary-static-assert)</p> + + + + Major + + + + + + + true + false + modernize-use-transparent-functors + modernize + + true + Use Transparent Functors + <p>Prefer transparent functors to non-transparent ones. When using transparent functors, the type does not need to be repeated. The code is easier to read, maintain and less prone to errors. It is not possible to introduce unwanted conversions.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Non-transparent functor</span> std::map&lt;<span class="dt">int</span>, std::string, std::greater&lt;<span class="dt">int</span>&gt;&gt; s; <span class="co">// Transparent functor.</span> std::map&lt;<span class="dt">int</span>, std::string, std::greater&lt;&gt;&gt; s; <span class="co">// Non-transparent functor</span> <span class="kw">using</span> MyFunctor = std::less&lt;MyType&gt;;</code></pre></div> <p>It is not always a safe transformation though. The following case will be untouched to preserve the semantics.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Non-transparent functor</span> std::map&lt;<span class="dt">const</span> <span class="dt">char</span> *, std::string, std::greater&lt;std::string&gt;&gt; s;</code></pre></div> <h5 id="options-55">Options</h5> <p>SafeMode</p> <p>If the option is set to true, the check will not diagnose cases where using a transparent functor cannot be guaranteed to produce identical results as the original code. The default value for this option is false.</p> <p>This check requires using C++14 or higher to run.</p> <p>(Clang-Tidy original name: modernize-use-transparent-functors)</p> + + + + Major + + + + + + + true + false + modernize-use-trailing-return-type + modernize + + true + Use Trailing Return Type + <p>Rewrites function signatures to use a trailing return type (introduced in C++11). This transformation is purely stylistic. The return type before the function name is replaced by auto and inserted after the function parameter list (and qualifiers).</p> <h5 id="example-5">Example</h5> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> f1(); <span class="kw">inline</span> <span class="dt">int</span> f2(<span class="dt">int</span> arg) <span class="kw">noexcept</span>; <span class="kw">virtual</span> <span class="dt">float</span> f3() <span class="dt">const</span> &amp;&amp; = <span class="kw">delete</span>;</code></pre></div> <p>transforms to:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">auto</span> f1() -&gt; <span class="dt">int</span>; <span class="kw">inline</span> <span class="kw">auto</span> f2(<span class="dt">int</span> arg) -&gt; <span class="dt">int</span> <span class="kw">noexcept</span>; <span class="kw">virtual</span> <span class="kw">auto</span> f3() <span class="dt">const</span> &amp;&amp; -&gt; <span class="dt">float</span> = <span class="kw">delete</span>;</code></pre></div> <h5 id="known-limitations-4">Known Limitations</h5> <p>The following categories of return types cannot be rewritten currently:</p> <ul> <li>function pointers</li> <li>member function pointers</li> <li>member pointers</li> </ul> <p>Unqualified names in the return type might erroneously refer to different entities after the rewrite. Preventing such errors requires a full lookup of all unqualified names present in the return type in the scope of the trailing return type location. This location includes e.g. function parameter names and members of the enclosing class (including all inherited classes). Such a lookup is currently not implemented.</p> <p>Given the following piece of code</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> S { <span class="dt">long</span> <span class="dt">long</span> value; }; S f(<span class="dt">unsigned</span> S) { <span class="kw">return</span> {S * <span class="dv">2</span>}; } <span class="kw">class</span> CC { <span class="dt">int</span> S; <span class="kw">struct</span> S m(); }; S CC::m() { <span class="kw">return</span> {<span class="dv">0</span>}; }</code></pre></div> <p>a careless rewrite would produce the following output:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> S { <span class="dt">long</span> <span class="dt">long</span> value; }; <span class="kw">auto</span> f(<span class="dt">unsigned</span> S) -&gt; S { <span class="kw">return</span> {S * <span class="dv">2</span>}; } <span class="co">// error</span> <span class="kw">class</span> CC { <span class="dt">int</span> S; <span class="kw">auto</span> m() -&gt; <span class="kw">struct</span> S; }; <span class="kw">auto</span> CC::m() -&gt; S { <span class="kw">return</span> {<span class="dv">0</span>}; } <span class="co">// error</span></code></pre></div> <p>This code fails to compile because the S in the context of f refers to the equally named function parameter. Similarly, the S in the context of m refers to the equally named class member. The check can currently only detect and avoid a clash with a function parameter name.</p> <p>(Clang-Tidy original name: modernize-use-trailing-return-type)</p> + + + + Major + + + + + + + true + false + modernize-use-using + modernize + + true + Use Using + <p>The check converts the usage of typedef with using keyword.</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">typedef</span> <span class="dt">int</span> variable; <span class="kw">class</span> Class{}; <span class="kw">typedef</span> <span class="dt">void</span> (Class::* MyPtrType)() <span class="dt">const</span>; <span class="kw">typedef</span> <span class="kw">struct</span> { <span class="dt">int</span> a; } R_t, *R_p;</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">using</span> variable = <span class="dt">int</span>; <span class="kw">class</span> Class{}; <span class="kw">using</span> MyPtrType = <span class="dt">void</span> (Class::*)() <span class="dt">const</span>; <span class="kw">using</span> R_t = <span class="kw">struct</span> { <span class="dt">int</span> a; }; <span class="kw">using</span> R_p = R_t*;</code></pre></div> <p>This check requires using C++11 or higher to run.</p> <h5 id="options-28">Options</h5> <p>IgnoreMacros</p> <p>If set to true, the check will not give warnings inside macros. Default is true.</p> <p>(Clang-Tidy original name: modernize-use-using)</p> + + + + Major + + + + + + + true + false + modernize-use-uncaught-exceptions + modernize + + true + Use Uncaught Exceptions + <p>This check will warn on calls to std::uncaught_exception and replace them with calls to std::uncaught_exceptions, since std::uncaught_exception was deprecated in C++17.</p> <p>Below are a few examples of what kind of occurrences will be found and what they will be replaced with.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#define MACRO1 std::uncaught_exception</span> <span class="ot">#define MACRO2 std::uncaught_exception</span> <span class="dt">int</span> uncaught_exception() { <span class="kw">return</span> <span class="dv">0</span>; } <span class="dt">int</span> main() { <span class="dt">int</span> res; res = uncaught_exception(); <span class="co">// No warning, since it is not the deprecated function from namespace std</span> res = MACRO2(); <span class="co">// Warning, but will not be replaced</span> res = std::uncaught_exception(); <span class="co">// Warning and replaced</span> <span class="kw">using</span> std::uncaught_exception; <span class="co">// Warning and replaced</span> res = uncaught_exception(); <span class="co">// Warning and replaced</span> }</code></pre></div> <p>After applying the fixes the code will look like the following:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#define MACRO1 std::uncaught_exception</span> <span class="ot">#define MACRO2 std::uncaught_exception</span> <span class="dt">int</span> uncaught_exception() { <span class="kw">return</span> <span class="dv">0</span>; } <span class="dt">int</span> main() { <span class="dt">int</span> res; res = uncaught_exception(); res = MACRO2(); res = std::uncaught_exceptions(); <span class="kw">using</span> std::uncaught_exceptions; res = uncaught_exceptions(); }</code></pre></div> <p>(Clang-Tidy original name: modernize-use-uncaught-exceptions)</p> + + + + Major + + + + + + + true + false + mpi-buffer-deref + mpi + + true + Buffer Deref + <p>This check verifies if a buffer passed to an MPI (Message Passing Interface) function is sufficiently dereferenced. Buffers should be passed as a single pointer or array. As MPI function signatures specify void * for their buffer types, insufficiently dereferenced buffers can be passed, like for example as double pointers or multidimensional arrays, without a compiler warning emitted.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// A double pointer is passed to the MPI function.</span> <span class="dt">char</span> *buf; MPI_Send(&amp;buf, <span class="dv">1</span>, MPI_CHAR, <span class="dv">0</span>, <span class="dv">0</span>, MPI_COMM_WORLD); <span class="co">// A multidimensional array is passed to the MPI function.</span> <span class="dt">short</span> buf[<span class="dv">1</span>][<span class="dv">1</span>]; MPI_Send(buf, <span class="dv">1</span>, MPI_SHORT, <span class="dv">0</span>, <span class="dv">0</span>, MPI_COMM_WORLD); <span class="co">// A pointer to an array is passed to the MPI function.</span> <span class="dt">short</span> *buf[<span class="dv">1</span>]; MPI_Send(buf, <span class="dv">1</span>, MPI_SHORT, <span class="dv">0</span>, <span class="dv">0</span>, MPI_COMM_WORLD);</code></pre></div> <p>(Clang-Tidy original name: mpi-buffer-deref)</p> + + + + Major + + + + + + + true + false + mpi-type-mismatch + mpi + + true + Type Mismatch + <p>This check verifies if buffer type and MPI (Message Passing Interface) datatype pairs match for used MPI functions. All MPI datatypes defined by the MPI standard (3.1) are verified by this check. User defined typedefs, custom MPI datatypes and null pointer constants are skipped, in the course of verification.</p> <p>Example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// In this case, the buffer type matches MPI datatype.</span> <span class="dt">char</span> buf; MPI_Send(&amp;buf, <span class="dv">1</span>, MPI_CHAR, <span class="dv">0</span>, <span class="dv">0</span>, MPI_COMM_WORLD); <span class="co">// In the following case, the buffer type does not match MPI datatype.</span> <span class="dt">int</span> buf; MPI_Send(&amp;buf, <span class="dv">1</span>, MPI_CHAR, <span class="dv">0</span>, <span class="dv">0</span>, MPI_COMM_WORLD);</code></pre></div> <p>(Clang-Tidy original name: mpi-type-mismatch)</p> + + + + Major + + + + + + + true + false + misc-definitions-in-headers + misc + + true + Definitions In Headers + <p>Finds non-extern non-inline function and variable definitions in header files, which can lead to potential ODR violations in case these headers are included from multiple translation units.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Foo.h</span> <span class="dt">int</span> a = <span class="dv">1</span>; <span class="co">// Warning: variable definition.</span> <span class="dt">extern</span> <span class="dt">int</span> d; <span class="co">// OK: extern variable.</span> <span class="kw">namespace</span> N { <span class="dt">int</span> e = <span class="dv">2</span>; <span class="co">// Warning: variable definition.</span> } <span class="co">// Warning: variable definition.</span> <span class="dt">const</span> <span class="dt">char</span>* str = <span class="st">&quot;foo&quot;</span>; <span class="co">// OK: internal linkage variable definitions are ignored for now.</span> <span class="co">// Although these might also cause ODR violations, we can be less certain and</span> <span class="co">// should try to keep the false-positive rate down.</span> <span class="dt">static</span> <span class="dt">int</span> b = <span class="dv">1</span>; <span class="dt">const</span> <span class="dt">int</span> c = <span class="dv">1</span>; <span class="dt">const</span> <span class="dt">char</span>* <span class="dt">const</span> str2 = <span class="st">&quot;foo&quot;</span>; <span class="kw">constexpr</span> <span class="dt">int</span> k = <span class="dv">1</span>; <span class="co">// Warning: function definition.</span> <span class="dt">int</span> g() { <span class="kw">return</span> <span class="dv">1</span>; } <span class="co">// OK: inline function definition is allowed to be defined multiple times.</span> <span class="kw">inline</span> <span class="dt">int</span> e() { <span class="kw">return</span> <span class="dv">1</span>; } <span class="kw">class</span> A { <span class="kw">public</span>: <span class="dt">int</span> f1() { <span class="kw">return</span> <span class="dv">1</span>; } <span class="co">// OK: implicitly inline member function definition is allowed.</span> <span class="dt">int</span> f2(); <span class="dt">static</span> <span class="dt">int</span> d; }; <span class="co">// Warning: not an inline member function definition.</span> <span class="dt">int</span> A::f2() { <span class="kw">return</span> <span class="dv">1</span>; } <span class="co">// OK: class static data member declaration is allowed.</span> <span class="dt">int</span> A::d = <span class="dv">1</span>; <span class="co">// OK: function template is allowed.</span> <span class="kw">template</span>&lt;<span class="kw">typename</span> T&gt; T f3() { T a = <span class="dv">1</span>; <span class="kw">return</span> a; } <span class="co">// Warning: full specialization of a function template is not allowed.</span> <span class="kw">template</span> &lt;&gt; <span class="dt">int</span> f3() { <span class="dt">int</span> a = <span class="dv">1</span>; <span class="kw">return</span> a; } <span class="kw">template</span> &lt;<span class="kw">typename</span> T&gt; <span class="kw">struct</span> B { <span class="dt">void</span> f1(); }; <span class="co">// OK: member function definition of a class template is allowed.</span> <span class="kw">template</span> &lt;<span class="kw">typename</span> T&gt; <span class="dt">void</span> B&lt;T&gt;::f1() {} <span class="kw">class</span> CE { <span class="kw">constexpr</span> <span class="dt">static</span> <span class="dt">int</span> i = <span class="dv">5</span>; <span class="co">// OK: inline variable definition.</span> }; <span class="kw">inline</span> <span class="dt">int</span> i = <span class="dv">5</span>; <span class="co">// OK: inline variable definition.</span> <span class="kw">constexpr</span> <span class="dt">int</span> f10() { <span class="kw">return</span> <span class="dv">0</span>; } <span class="co">// OK: constexpr function implies inline.</span> <span class="co">// OK: C++14 variable templates are inline.</span> <span class="kw">template</span> &lt;<span class="kw">class</span> T&gt; <span class="kw">constexpr</span> T pi = T(<span class="fl">3.1415926L</span>);</code></pre></div> <h5 id="options-73">Options</h5> <p>HeaderFileExtensions</p> <p>A comma-separated list of filename extensions of header files (the filename extensions should not include “.” prefix). Default is “h,hh,hpp,hxx”. For header files without an extension, use an empty string (if there are no other desired extensions) or leave an empty element in the list. e.g., “h,hh,hpp,hxx,” (note the trailing comma).</p> <p>UseHeaderFileExtension</p> <p>When true, the check will use the file extension to distinguish header files. Default is true.</p> <p>(Clang-Tidy original name: misc-definitions-in-headers)</p> + + + + Major + + + + + + + true + false + misc-misplaced-const + misc + + true + Misplaced Const + <p>This check diagnoses when a const qualifier is applied to a typedef/ using to a pointer type rather than to the pointee, because such constructs are often misleading to developers because the const applies to the pointer rather than the pointee.</p> <p>For instance, in the following code, the resulting type is int * const rather than const int *:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">typedef</span> <span class="dt">int</span> *int_ptr; <span class="dt">void</span> f(<span class="dt">const</span> int_ptr ptr) { *ptr = <span class="dv">0</span>; <span class="co">// potentially quite unexpectedly the int can be modified here</span> ptr = <span class="dv">0</span>; <span class="co">// does not compile</span> }</code></pre></div> <p>The check does not diagnose when the underlying typedef/using type is a pointer to a const type or a function pointer type. This is because the const qualifier is less likely to be mistaken because it would be redundant (or disallowed) on the underlying pointee type.</p> <p>(Clang-Tidy original name: misc-misplaced-const)</p> + + + + Major + + + + + + + true + false + misc-non-copyable-objects + misc + + true + Non Copyable Objects + <p>cert-fio38-c redirects here as an alias for this check.</p> <p>The check flags dereferences and non-pointer declarations of objects that are not meant to be passed by value, such as C FILE objects or POSIX pthread_mutex_t objects.</p> <p>This check corresponds to CERT C++ Coding Standard rule <a href="https://www.securecoding.cert.org/confluence/display/c/FIO38-C.+Do+not+copy+a+FILE+object">FIO38-C. Do not copy a FILE object</a>.</p> <p>(Clang-Tidy original name: misc-non-copyable-objects)</p> + + + + Major + + + + + + + true + false + misc-new-delete-overloads + misc + + true + New Delete Overloads + <p>cert-dcl54-cpp redirects here as an alias for this check.</p> <p>The check flags overloaded operator new() and operator delete() functions that do not have a corresponding free store function defined within the same scope. For instance, the check will flag a class implementation of a non-placement operator new() when the class does not also define a non-placement operator delete() function as well.</p> <p>The check does not flag implicitly-defined operators, deleted or private operators, or placement operators.</p> <p>This check corresponds to CERT C++ Coding Standard rule <a href="https://www.securecoding.cert.org/confluence/display/cplusplus/DCL54-CPP.+Overload+allocation+and+deallocation+functions+as+a+pair+in+the+same+scope">DCL54-CPP. Overload allocation and deallocation functions as a pair in the same scope</a>.</p> <p>(Clang-Tidy original name: misc-new-delete-overloads)</p> + + + + Major + + + + + + + true + false + misc-non-private-member-variables-in-classes + misc + + true + Non Private Member Variables In Classes + <p>cppcoreguidelines-non-private-member-variables-in-classes redirects here as an alias for this check.</p> <p>Finds classes that contain non-static data members in addition to user-declared non-static member functions and diagnose all data members declared with a non-public access specifier. The data members should be declared as private and accessed through member functions instead of exposed to derived classes or class consumers.</p> <h5 id="options-2">Options</h5> <p>IgnoreClassesWithAllMemberVariablesBeingPublic</p> <p>Allows to completely ignore classes if <strong>all</strong> the member variables in that class a declared with a public access specifier.</p> <p>IgnorePublicMemberVariables</p> <p>Allows to ignore (not diagnose) <strong>all</strong> the member variables declared with a public access specifier.</p> <p>(Clang-Tidy original name: misc-non-private-member-variables-in-classes)</p> + + + + Major + + + + + + + true + false + misc-no-recursion + misc + + true + No Recursion + <p>Finds strongly connected functions (by analyzing the call graph for SCC’s (Strongly Connected Components) that are loops), diagnoses each function in the cycle, and displays one example of a possible call graph loop (recursion).</p> <p>References:</p> <ul> <li>CERT C++ Coding Standard rule <a href="https://wiki.sei.cmu.edu/confluence/display/cplusplus/DCL56-CPP.+Avoid+cycles+during+initialization+of+static+objects">DCL56-CPP. Avoid cycles during initialization of static objects</a>.</li> <li>JPL Institutional Coding Standard for the C Programming Language (JPL DOCID D-60411) rule 2.4 Do not use direct or indirect recursion.</li> <li>OpenCL Specification, Version 1.2 rule <a href="https://www.khronos.org/registry/OpenCL/specs/opencl-1.2.pdf">6.9 Restrictions: i. Recursion is not supported.</a>.</li> </ul> <p>Limitations:</p> <ul> <li>The check does not handle calls done through function pointers</li> <li>The check does not handle C++ destructors</li> </ul> <p>(Clang-Tidy original name: misc-no-recursion)</p> + + + + Major + + + + + + + true + false + misc-redundant-expression + misc + + true + Redundant Expression + <p>Detect redundant expressions which are typically errors due to copy-paste.</p> <p>Depending on the operator expressions may be</p> <ul> <li>redundant,</li> <li>always true,</li> <li>always false,</li> <li>always a constant (zero or one).</li> </ul> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">((x<span class="dv">+1</span>) | (x<span class="dv">+1</span>)) <span class="co">// (x+1) is redundant</span> (p-&gt;x == p-&gt;x) <span class="co">// always true</span> (p-&gt;x &lt; p-&gt;x) <span class="co">// always false</span> (speed - speed + <span class="dv">1</span> == <span class="dv">12</span>) <span class="co">// speed - speed is always zero</span></code></pre></div> <p>(Clang-Tidy original name: misc-redundant-expression)</p> + + + + Major + + + + + + + true + false + misc-static-assert + misc + + true + Static Assert + <p>cert-dcl03-c redirects here as an alias for this check.</p> <p>Replaces assert() with static_assert() if the condition is evaluatable at compile time.</p> <p>The condition of static_assert() is evaluated at compile time which is safer and more efficient.</p> <p>(Clang-Tidy original name: misc-static-assert)</p> + + + + Major + + + + + + + true + false + misc-throw-by-value-catch-by-reference + misc + + true + Throw By Value Catch By Reference + <p>cert-err09-cpp redirects here as an alias for this check. cert-err61-cpp redirects here as an alias for this check.</p> <p>Finds violations of the rule “Throw by value, catch by reference” presented for example in “C++ Coding Standards” by H. Sutter and A. Alexandrescu, as well as the CERT C++ Coding Standard rule <a href="https://wiki.sei.cmu.edu/confluence/display/cplusplus/ERR61-CPP.+Catch+exceptions+by+lvalue+reference">ERR61-CPP. Catch exceptions by lvalue reference</a>.</p> <p>Exceptions:</p> <ul> <li>Throwing string literals will not be flagged despite being a pointer. They are not susceptible to slicing and the usage of string literals is idomatic.</li> <li>Catching character pointers (char, wchar_t, unicode character types) will not be flagged to allow catching sting literals.</li> <li>Moved named values will not be flagged as not throwing an anonymous temporary. In this case we can be sure that the user knows that the object can’t be accessed outside catch blocks handling the error.</li> <li>Throwing function parameters will not be flagged as not throwing an anonymous temporary. This allows helper functions for throwing.</li> <li>Re-throwing caught exception variables will not be flragged as not throwing an anonymous temporary. Although this can usually be done by just writing throw; it happens often enough in real code.</li> </ul> <h5 id="options-61">Options</h5> <p>CheckThrowTemporaries</p> <p>Triggers detection of violations of the CERT recommendation ERR09-CPP. Throw anonymous temporaries. Default is true.</p> <p>WarnOnLargeObject</p> <p>Also warns for any large, trivial object caught by value. Catching a large object by value is not dangerous but affects the performance negatively. The maximum size of an object allowed to be caught without warning can be set using the MaxSize option. Default is false.</p> <p>MaxSize</p> <p>Determines the maximum size of an object allowed to be caught without warning. Only applicable if <a href="#cmdoption-arg-warnonlargeobject">WarnOnLargeObject</a> is set to true. If the option is set by the user to std::numeric_limits<uint64_t>::max() then it reverts to the default value. Default is the size of size_t.</p> <p>(Clang-Tidy original name: misc-throw-by-value-catch-by-reference)</p> + + + + Major + + + + + + + true + false + misc-unused-alias-decls + misc + + true + Unused Alias Decls + <p>Finds unused namespace alias declarations.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">namespace</span> my_namespace { <span class="kw">class</span> C {}; } <span class="kw">namespace</span> unused_alias = ::my_namespace;</code></pre></div> <p>(Clang-Tidy original name: misc-unused-alias-decls)</p> + + + + Major + + + + + + + true + false + misc-unconventional-assign-operator + misc + + true + Unconventional Assign Operator + <p>Finds declarations of assign operators with the wrong return and/or argument types and definitions with good return type but wrong return statements.</p> <ul> <li>The return type must be Class&amp;.</li> <li>Works with move-assign and assign by value.</li> <li>Private and deleted operators are ignored.</li> <li>The operator must always return *this.</li> </ul> <p>(Clang-Tidy original name: misc-unconventional-assign-operator)</p> + + + + Major + + + + + + + true + false + misc-unused-parameters + misc + + true + Unused Parameters + <p>Finds unused function parameters. Unused parameters may signify a bug in the code (e.g. when a different parameter is used instead). The suggested fixes either comment parameter name out or remove the parameter completely, if all callers of the function are in the same translation unit and can be updated.</p> <p>The check is similar to the -Wunused-parameter compiler diagnostic and can be used to prepare a codebase to enabling of that diagnostic. By default the check is more permissive (see <a href="performance-inefficient-string-concatenation.html#cmdoption-arg-strictmode">StrictMode</a>).</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> a(<span class="dt">int</span> i) { <span class="co">/*some code that doesn&#39;t use `i`*/</span> } <span class="co">// becomes</span> <span class="dt">void</span> a(<span class="dt">int</span> <span class="co">/*i*/</span>) { <span class="co">/*some code that doesn&#39;t use `i`*/</span> }</code></pre></div> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">static</span> <span class="dt">void</span> staticFunctionA(<span class="dt">int</span> i); <span class="dt">static</span> <span class="dt">void</span> staticFunctionA(<span class="dt">int</span> i) { <span class="co">/*some code that doesn&#39;t use `i`*/</span> } <span class="co">// becomes</span> <span class="dt">static</span> <span class="dt">void</span> staticFunctionA() <span class="dt">static</span> <span class="dt">void</span> staticFunctionA() { <span class="co">/*some code that doesn&#39;t use `i`*/</span> }</code></pre></div> <h5 id="options-12">Options</h5> <p>StrictMode</p> <p>When false (default value), the check will ignore trivially unused parameters, i.e. when the corresponding function has an empty body (and in case of constructors - no constructor initializers). When the function body is empty, an unused parameter is unlikely to be unnoticed by a human reader, and there’s basically no place for a bug to hide.</p> <p>(Clang-Tidy original name: misc-unused-parameters)</p> + + + + Major + + + + + + + true + false + misc-uniqueptr-reset-release + misc + + true + Uniqueptr Reset Release + <p>Find and replace unique_ptr::reset(release()) with std::move().</p> <p>Example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::unique_ptr&lt;Foo&gt; x, y; x.reset(y.release()); -&gt; x = std::move(y);</code></pre></div> <p>If y is already rvalue, std::move() is not added. x and y can also be std::unique_ptr<Foo>*.</p> <p>(Clang-Tidy original name: misc-uniqueptr-reset-release)</p> + + + + Major + + + + + + + true + false + misc-unused-using-decls + misc + + true + Unused Using Decls + <p>Finds unused using declarations.</p> <p>Example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">namespace</span> n { <span class="kw">class</span> C; } <span class="kw">using</span> n::C; <span class="co">// Never actually used.</span></code></pre></div> <p>(Clang-Tidy original name: misc-unused-using-decls)</p> + + + + Major + + + + + + + false + false + objc-avoid-nserror-init + objc + + true + Avoid Nserror Init + <p>Finds improper initialization of NSError objects.</p> <p>According to Apple developer document, we should always use factory method errorWithDomain:code:userInfo: to create new NSError objects instead of [NSError alloc] init]. Otherwise it will lead to a warning message during runtime.</p> <p>The corresponding information about NSError creation: <a href="https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ErrorHandlingCocoa/CreateCustomizeNSError/CreateCustomizeNSError.html" class="uri">https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ErrorHandlingCocoa/CreateCustomizeNSError/CreateCustomizeNSError.html</a></p> <p>(Clang-Tidy original name: objc-avoid-nserror-init)</p> + + + + Major + + + + + + + false + false + objc-dealloc-in-category + objc + + true + Dealloc In Category + <p>Finds implementations of -dealloc in Objective-C categories. The category implementation will override any -dealloc in the class implementation, potentially causing issues.</p> <p>Classes implement -dealloc to perform important actions to deallocate an object. If a category on the class implements -dealloc, it will override the class’s implementation and unexpected deallocation behavior may occur.</p> <p>(Clang-Tidy original name: objc-dealloc-in-category)</p> + + + + Major + + + + + + + false + false + objc-forbidden-subclassing + objc + + true + Forbidden Subclassing + <p>Finds Objective-C classes which are subclasses of classes which are not designed to be subclassed.</p> <p>By default, includes a list of Objective-C classes which are publicly documented as not supporting subclassing.</p> <p>Note</p> <p>Instead of using this check, for code under your control, you should add <strong>attribute</strong>((objc_subclassing_restricted)) before your <span class="citation">@interface</span> declarations to ensure the compiler prevents others from subclassing your Objective-C classes. See <a href="https://clang.llvm.org/docs/AttributeReference.html\#objc-subclassing-restricted" class="uri">https://clang.llvm.org/docs/AttributeReference.html\#objc-subclassing-restricted</a></p> <h5 id="options-39">Options</h5> <p>ForbiddenSuperClassNames</p> <p>Semicolon-separated list of names of Objective-C classes which do not support subclassing.</p> <p>Defaults to ABNewPersonViewController;ABPeoplePickerNavigationController;ABPersonViewController;ABUnknownPersonViewController;NSHashTable;NSMapTable;NSPointerArray;NSPointerFunctions;NSTimer;UIActionSheet;UIAlertView;UIImagePickerController;UITextInputMode;UIWebView.</p> <p>(Clang-Tidy original name: objc-forbidden-subclassing)</p> + + + + Major + + + + + + + false + false + objc-missing-hash + objc + + true + Missing Hash + <p>Finds Objective-C implementations that implement -isEqual: without also appropriately implementing -hash.</p> <p>Apple documentation highlights that objects that are equal must have the same hash value: <a href="https://developer.apple.com/documentation/objectivec/1418956-nsobject/1418795-isequal?language=objc" class="uri">https://developer.apple.com/documentation/objectivec/1418956-nsobject/1418795-isequal?language=objc</a></p> <p>Note that the check only verifies the presence of -hash in scenarios where its omission could result in unexpected behavior. The verification of the implementation of -hash is the responsibility of the developer, e.g., through the addition of unit tests to verify the implementation.</p> <p>(Clang-Tidy original name: objc-missing-hash)</p> + + + + Major + + + + + + + false + false + objc-nsinvocation-argument-lifetime + objc + + true + Nsinvocation Argument Lifetime + <p>Finds calls to NSInvocation methods under ARC that don’t have proper argument object lifetimes. When passing Objective-C objects as parameters to the NSInvocation methods getArgument:atIndex: and getReturnValue:, the values are copied by value into the argument pointer, which leads to to incorrect releasing behavior if the object pointers are not declared __unsafe_unretained.</p> <p>For code:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">id arg; [invocation getArgument:&amp;arg atIndex:<span class="dv">2</span>]; __strong id returnValue; [invocation getReturnValue:&amp;returnValue];</code></pre></div> <p>The fix will be:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">__unsafe_unretained id arg; [invocation getArgument:&amp;arg atIndex:<span class="dv">2</span>]; __unsafe_unretained id returnValue; [invocation getReturnValue:&amp;returnValue];</code></pre></div> <p>The check will warn on being passed instance variable references that have lifetimes other than __unsafe_unretained, but does not propose a fix:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// &quot;id _returnValue&quot; is declaration of instance variable of class.</span> [invocation getReturnValue:&amp;self-&gt;_returnValue];</code></pre></div> <p>(Clang-Tidy original name: objc-nsinvocation-argument-lifetime)</p> + + + + Major + + + + + + + false + false + objc-property-declaration + objc + + true + Property Declaration + <p>Finds property declarations in Objective-C files that do not follow the pattern of property names in Apple’s programming guide. The property name should be in the format of Lower Camel Case.</p> <p>For code:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="er">@</span>property(nonatomic, assign) <span class="dt">int</span> LowerCamelCase;</code></pre></div> <p>The fix will be:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="er">@</span>property(nonatomic, assign) <span class="dt">int</span> lowerCamelCase;</code></pre></div> <p>The check will only fix ‘CamelCase’ to ‘camelCase’. In some other cases we will only provide warning messages since the property name could be complicated. Users will need to come up with a proper name by their own.</p> <p>This check also accepts special acronyms as prefixes or suffixes. Such prefixes or suffixes will suppress the Lower Camel Case check according to the guide: <a href="https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingBasics.html\#//apple_ref/doc/uid/20001281-1002931-BBCFHEAB" class="uri">https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingBasics.html\#//apple_ref/doc/uid/20001281-1002931-BBCFHEAB</a></p> <p>For a full list of well-known acronyms: <a href="https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/APIAbbreviations.html\#//apple_ref/doc/uid/20001285-BCIHCGAE" class="uri">https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/APIAbbreviations.html\#//apple_ref/doc/uid/20001285-BCIHCGAE</a></p> <p>The corresponding style rule: <a href="https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingIvarsAndTypes.html\#//apple_ref/doc/uid/20001284-1001757" class="uri">https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingIvarsAndTypes.html\#//apple_ref/doc/uid/20001284-1001757</a></p> <p>The check will also accept property declared in category with a prefix of lowercase letters followed by a ‘_’ to avoid naming conflict. For example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="er">@</span>property(nonatomic, assign) <span class="dt">int</span> abc_lowerCamelCase;</code></pre></div> <p>The corresponding style rule: <a href="https://developer.apple.com/library/content/qa/qa1908/_index.html" class="uri">https://developer.apple.com/library/content/qa/qa1908/_index.html</a></p> <p>(Clang-Tidy original name: objc-property-declaration)</p> + + + + Major + + + + + + + false + false + objc-super-self + objc + + true + Super Self + <p>Finds invocations of -self on super instances in initializers of subclasses of NSObject and recommends calling a superclass initializer instead.</p> <p>Invoking -self on super instances in initializers is a common programmer error when the programmer’s original intent is to call a superclass initializer. Failing to call a superclass initializer breaks initializer chaining and can result in invalid object initialization.</p> <p>(Clang-Tidy original name: objc-super-self)</p> + + + + Major + + + + + + + true + false + openmp-exception-escape + openmp + + true + Exception Escape + <p>Analyzes OpenMP Structured Blocks and checks that no exception escapes out of the Structured Block it was thrown in.</p> <p>As per the OpenMP specification, a structured block is an executable statement, possibly compound, with a single entry at the top and a single exit at the bottom. Which means, throw may not be used to to ‘exit’ out of the structured block. If an exception is not caught in the same structured block it was thrown in, the behaviour is undefined.</p> <p>FIXME: this check does not model SEH, setjmp/longjmp.</p> <p>WARNING! This check may be expensive on large source files.</p> <h5 id="options-20">Options</h5> <p>IgnoredExceptions</p> <p>Comma-separated list containing type names which are not counted as thrown exceptions in the check. Default value is an empty string.</p> <p>(Clang-Tidy original name: openmp-exception-escape)</p> + + + + Major + + + + + + + true + false + openmp-use-default-none + openmp + + true + Use Default None + <p>Finds OpenMP directives that are allowed to contain a default clause, but either don’t specify it or the clause is specified but with the kind other than none, and suggests to use the default(none) clause.</p> <p>Using default(none) clause forces developers to explicitly specify data sharing attributes for the variables referenced in the construct, thus making it obvious which variables are referenced, and what is their data sharing attribute, thus increasing readability and possibly making errors easier to spot.</p> <h5 id="example-3">Example</h5> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// ``for`` directive can not have ``default`` clause, no diagnostics.</span> <span class="dt">void</span> n0(<span class="dt">const</span> <span class="dt">int</span> a) { <span class="ot">#pragma omp for</span> <span class="kw">for</span> (<span class="dt">int</span> b = <span class="dv">0</span>; b &lt; a; b++) ; } <span class="co">// ``parallel`` directive.</span> <span class="co">// ``parallel`` directive can have ``default`` clause, but said clause is not</span> <span class="co">// specified, diagnosed.</span> <span class="dt">void</span> p0_0() { <span class="ot">#pragma omp parallel</span> ; <span class="co">// WARNING: OpenMP directive ``parallel`` does not specify ``default``</span> <span class="co">// clause. Consider specifying ``default(none)`` clause.</span> } <span class="co">// ``parallel`` directive can have ``default`` clause, and said clause is</span> <span class="co">// specified, with ``none`` kind, all good.</span> <span class="dt">void</span> p0_1() { <span class="ot">#pragma omp parallel default(none)</span> ; } <span class="co">// ``parallel`` directive can have ``default`` clause, and said clause is</span> <span class="co">// specified, but with ``shared`` kind, which is not ``none``, diagnose.</span> <span class="dt">void</span> p0_2() { <span class="ot">#pragma omp parallel default(shared)</span> ; <span class="co">// WARNING: OpenMP directive ``parallel`` specifies ``default(shared)``</span> <span class="co">// clause. Consider using ``default(none)`` clause instead.</span> } <span class="co">// ``parallel`` directive can have ``default`` clause, and said clause is</span> <span class="co">// specified, but with ``firstprivate`` kind, which is not ``none``, diagnose.</span> <span class="dt">void</span> p0_3() { <span class="ot">#pragma omp parallel default(firstprivate)</span> ; <span class="co">// WARNING: OpenMP directive ``parallel`` specifies ``default(firstprivate)``</span> <span class="co">// clause. Consider using ``default(none)`` clause instead.</span> }</code></pre></div> <p>(Clang-Tidy original name: openmp-use-default-none)</p> + + + + Major + + + + + + + true + false + performance-for-range-copy + performance + + true + For Range Copy + <p>Finds C++11 for ranges where the loop variable is copied in each iteration but it would suffice to obtain it by const reference.</p> <p>The check is only applied to loop variables of types that are expensive to copy which means they are not trivially copyable or have a non-trivial copy constructor or destructor.</p> <p>To ensure that it is safe to replace the copy with a const reference the following heuristic is employed:</p> <ol style="list-style-type: decimal"> <li>The loop variable is const qualified.</li> <li>The loop variable is not const, but only const methods or operators are invoked on it, or it is used as const reference or value argument in constructors or function calls.</li> </ol> <h5 id="options-9">Options</h5> <p>WarnOnAllAutoCopies</p> <p>When true, warns on any use of auto as the type of the range-based for loop variable. Default is false.</p> <p>AllowedTypes</p> <p>A semicolon-separated list of names of types allowed to be copied in each iteration. Regular expressions are accepted, e.g. [Rr]ef(erence)?$ matches every type with suffix Ref, ref, Reference and reference. The default is empty.</p> <p>(Clang-Tidy original name: performance-for-range-copy)</p> + + + + Major + + + + + + + true + false + performance-faster-string-find + performance + + true + Faster String Find + <p>Optimize calls to std::string::find() and friends when the needle passed is a single character string literal. The character literal overload is more efficient.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">str.find(<span class="st">&quot;A&quot;</span>); <span class="co">// becomes</span> str.find(<span class="st">&#39;A&#39;</span>);</code></pre></div> <h5 id="options-10">Options</h5> <p>StringLikeClasses</p> <p>Semicolon-separated list of names of string-like classes. By default only ::std::basic_string and ::std::basic_string_view are considered. The check will only consider member functions named find, rfind, find_first_of, find_first_not_of, find_last_of, or find_last_not_of within these classes.</p> <p>(Clang-Tidy original name: performance-faster-string-find)</p> + + + + Major + + + + + + + true + false + performance-inefficient-algorithm + performance + + true + Inefficient Algorithm + <p>Warns on inefficient use of STL algorithms on associative containers.</p> <p>Associative containers implements some of the algorithms as methods which should be preferred to the algorithms in the algorithm header. The methods can take advantage of the order of the elements.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::set&lt;<span class="dt">int</span>&gt; s; <span class="kw">auto</span> it = std::find(s.begin(), s.end(), <span class="dv">43</span>); <span class="co">// becomes</span> <span class="kw">auto</span> it = s.find(<span class="dv">43</span>);</code></pre></div> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::set&lt;<span class="dt">int</span>&gt; s; <span class="kw">auto</span> c = std::count(s.begin(), s.end(), <span class="dv">43</span>); <span class="co">// becomes</span> <span class="kw">auto</span> c = s.count(<span class="dv">43</span>);</code></pre></div> <p>(Clang-Tidy original name: performance-inefficient-algorithm)</p> + + + + Major + + + + + + + true + false + performance-implicit-conversion-in-loop + performance + + true + Implicit Conversion In Loop + <p>This warning appears in a range-based loop with a loop variable of const ref type where the type of the variable does not match the one returned by the iterator. This means that an implicit conversion happens, which can for example result in expensive deep copies.</p> <p>Example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">map&lt;<span class="dt">int</span>, vector&lt;string&gt;&gt; my_map; <span class="kw">for</span> (<span class="dt">const</span> pair&lt;<span class="dt">int</span>, vector&lt;string&gt;&gt;&amp; p : my_map) {} <span class="co">// The iterator type is in fact pair&lt;const int, vector&lt;string&gt;&gt;, which means</span> <span class="co">// that the compiler added a conversion, resulting in a copy of the vectors.</span></code></pre></div> <p>The easiest solution is usually to use const auto&amp; instead of writing the type manually.</p> <p>(Clang-Tidy original name: performance-implicit-conversion-in-loop)</p> + + + + Major + + + + + + + true + false + performance-inefficient-string-concatenation + performance + + true + Inefficient String Concatenation + <p>This check warns about the performance overhead arising from concatenating strings using the operator+, for instance:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::string a(<span class="st">&quot;Foo&quot;</span>), b(<span class="st">&quot;Bar&quot;</span>); a = a + b;</code></pre></div> <p>Instead of this structure you should use operator+= or std::string’s (std::basic_string) class member function append(). For instance:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::string a(<span class="st">&quot;Foo&quot;</span>), b(<span class="st">&quot;Baz&quot;</span>); <span class="kw">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; <span class="dv">20000</span>; ++i) { a = a + <span class="st">&quot;Bar&quot;</span> + b; }</code></pre></div> <p>Could be rewritten in a greatly more efficient way like:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::string a(<span class="st">&quot;Foo&quot;</span>), b(<span class="st">&quot;Baz&quot;</span>); <span class="kw">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; <span class="dv">20000</span>; ++i) { a.append(<span class="st">&quot;Bar&quot;</span>).append(b); }</code></pre></div> <p>And this can be rewritten too:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> f(<span class="dt">const</span> std::string&amp;) {} std::string a(<span class="st">&quot;Foo&quot;</span>), b(<span class="st">&quot;Baz&quot;</span>); <span class="dt">void</span> g() { f(a + <span class="st">&quot;Bar&quot;</span> + b); }</code></pre></div> <p>In a slightly more efficient way like:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> f(<span class="dt">const</span> std::string&amp;) {} std::string a(<span class="st">&quot;Foo&quot;</span>), b(<span class="st">&quot;Baz&quot;</span>); <span class="dt">void</span> g() { f(std::string(a).append(<span class="st">&quot;Bar&quot;</span>).append(b)); }</code></pre></div> <h5 id="options-46">Options</h5> <p>StrictMode</p> <p>When false, the check will only check the string usage in while, for and for-range statements. Default is false.</p> <p>(Clang-Tidy original name: performance-inefficient-string-concatenation)</p> + + + + Major + + + + + + + true + false + performance-inefficient-vector-operation + performance + + true + Inefficient Vector Operation + <p>Finds possible inefficient std::vector operations (e.g. push_back, emplace_back) that may cause unnecessary memory reallocations.</p> <p>It can also find calls that add element to protobuf repeated field in a loop without calling Reserve() before the loop. Calling Reserve() first can avoid unnecessary memory reallocations.</p> <p>Currently, the check only detects following kinds of loops with a single statement body:</p> <ul> <li>Counter-based for loops start with 0:</li> </ul> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::vector&lt;<span class="dt">int</span>&gt; v; <span class="kw">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; n; ++i) { v.push_back(n); <span class="co">// This will trigger the warning since the push_back may cause multiple</span> <span class="co">// memory reallocations in v. This can be avoid by inserting a &#39;reserve(n)&#39;</span> <span class="co">// statement before the for statement.</span> } SomeProto p; <span class="kw">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; n; ++i) { p.add_xxx(n); <span class="co">// This will trigger the warning since the add_xxx may cause multiple memory</span> <span class="co">// reallocations. This can be avoid by inserting a</span> <span class="co">// &#39;p.mutable_xxx().Reserve(n)&#39; statement before the for statement.</span> }</code></pre></div> <ul> <li>For-range loops like for (range-declaration : range_expression), the type of range_expression can be std::vector, std::array, std::deque, std::set, std::unordered_set, std::map, std::unordered_set:</li> </ul> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::vector&lt;<span class="dt">int</span>&gt; data; std::vector&lt;<span class="dt">int</span>&gt; v; <span class="kw">for</span> (<span class="kw">auto</span> element : data) { v.push_back(element); <span class="co">// This will trigger the warning since the &#39;push_back&#39; may cause multiple</span> <span class="co">// memory reallocations in v. This can be avoid by inserting a</span> <span class="co">// &#39;reserve(data.size())&#39; statement before the for statement.</span> }</code></pre></div> <h5 id="options-48">Options</h5> <p>VectorLikeClasses</p> <p>Semicolon-separated list of names of vector-like classes. By default only ::std::vector is considered.</p> <p>EnableProto</p> <p>When true, the check will also warn on inefficient operations for proto repeated fields. Otherwise, the check only warns on inefficient vector operations. Default is false.</p> <p>(Clang-Tidy original name: performance-inefficient-vector-operation)</p> + + + + Major + + + + + + + true + false + performance-move-const-arg + performance + + true + Move Const Arg + <p>The check warns</p> <ul> <li>if std::move() is called with a constant argument,</li> <li>if std::move() is called with an argument of a trivially-copyable type,</li> <li>if the result of std::move() is passed as a const reference argument.</li> </ul> <p>In all three cases, the check will suggest a fix that removes the std::move().</p> <p>Here are examples of each of the three cases:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">const</span> string s; <span class="kw">return</span> std::move(s); <span class="co">// Warning: std::move of the const variable has no effect</span> <span class="dt">int</span> x; <span class="kw">return</span> std::move(x); <span class="co">// Warning: std::move of the variable of a trivially-copyable type has no effect</span> <span class="dt">void</span> f(<span class="dt">const</span> string &amp;s); string s; f(std::move(s)); <span class="co">// Warning: passing result of std::move as a const reference argument; no move will actually happen</span></code></pre></div> <h5 id="options-81">Options</h5> <p>CheckTriviallyCopyableMove</p> <p>If true, enables detection of trivially copyable types that do not have a move constructor. Default is true.</p> <p>(Clang-Tidy original name: performance-move-const-arg)</p> + + + + Major + + + + + + + true + false + performance-move-constructor-init + performance + + true + Move Constructor Init + <p>“cert-oop11-cpp” redirects here as an alias for this check.</p> <p>The check flags user-defined move constructors that have a ctor-initializer initializing a member or base class through a copy constructor instead of a move constructor.</p> <h5 id="options-70">Options</h5> <p>IncludeStyle</p> <p>A string specifying which include-style is used, llvm or google. Default is llvm.</p> <p>(Clang-Tidy original name: performance-move-constructor-init)</p> + + + + Major + + + + + + + true + false + performance-no-automatic-move + performance + + true + No Automatic Move + <p>Finds local variables that cannot be automatically moved due to constness.</p> <p>Under <a href="https://en.cppreference.com/w/cpp/language/return#automatic_move_from_local_variables_and_parameters">certain conditions</a>, local values are automatically moved out when returning from a function. A common mistake is to declare local lvalue variables const, which prevents the move.</p> <p>Example <a href="https://godbolt.org/z/x7SYYA">[1]</a>:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">StatusOr&lt;std::vector&lt;<span class="dt">int</span>&gt;&gt; Cool() { std::vector&lt;<span class="dt">int</span>&gt; obj = ...; <span class="kw">return</span> obj; <span class="co">// calls StatusOr::StatusOr(std::vector&lt;int&gt;&amp;&amp;)</span> } StatusOr&lt;std::vector&lt;<span class="dt">int</span>&gt;&gt; NotCool() { <span class="dt">const</span> std::vector&lt;<span class="dt">int</span>&gt; obj = ...; <span class="kw">return</span> obj; <span class="co">// calls `StatusOr::StatusOr(const std::vector&lt;int&gt;&amp;)`</span> }</code></pre></div> <p>The former version (Cool) should be preferred over the latter (Uncool) as it will avoid allocations and potentially large memory copies.</p> <h5 id="semantics">Semantics</h5> <p>In the example above, StatusOr::StatusOr(T&amp;&amp;) have the same semantics as long as the copy and move constructors for T have the same semantics. Note that there is no guarantee that S::S(T&amp;&amp;) and S::S(const T&amp;) have the same semantics for any single S, so we’re not providing automated fixes for this check, and judgement should be exerted when making the suggested changes.</p> <h5 id="wreturn-std-move">-Wreturn-std-move</h5> <p>Another case where the move cannot happen is the following:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">StatusOr&lt;std::vector&lt;<span class="dt">int</span>&gt;&gt; Uncool() { std::vector&lt;<span class="dt">int</span>&gt;&amp;&amp; obj = ...; <span class="kw">return</span> obj; <span class="co">// calls `StatusOr::StatusOr(const std::vector&lt;int&gt;&amp;)`</span> }</code></pre></div> <p>In that case the fix is more consensual: just return std::move(obj). This is handled by the -Wreturn-std-move warning.</p> <p>(Clang-Tidy original name: performance-no-automatic-move)</p> + + + + Major + + + + + + + true + false + performance-no-int-to-ptr + performance + + true + No Int To Ptr + <p>Diagnoses every integer to pointer cast.</p> <p>While casting an (integral) pointer to an integer is obvious - you just get the integral value of the pointer, casting an integer to an (integral) pointer is deceivingly different. While you will get a pointer with that integral value, if you got that integral value via a pointer-to-integer cast originally, the new pointer will lack the provenance information from the original pointer.</p> <p>So while (integral) pointer to integer casts are effectively no-ops, and are transparent to the optimizer, integer to (integral) pointer casts are <em>NOT</em> transparent, and may conceal information from optimizer.</p> <p>While that may be the intention, it is not always so. For example, let’s take a look at a routine to align the pointer up to the multiple of 16: The obvious, naive implementation for that is:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">char</span>* src(<span class="dt">char</span>* maybe_underbiased_ptr) { uintptr_t maybe_underbiased_intptr = (uintptr_t)maybe_underbiased_ptr; uintptr_t aligned_biased_intptr = maybe_underbiased_intptr + <span class="dv">15</span>; uintptr_t aligned_intptr = aligned_biased_intptr &amp; (~<span class="dv">15</span>); <span class="kw">return</span> (<span class="dt">char</span>*)aligned_intptr; <span class="co">// warning: avoid integer to pointer casts [performance-no-int-to-ptr]</span> }</code></pre></div> <p>The check will rightfully diagnose that cast.</p> <p>But when provenance concealment is not the goal of the code, but an accident, this example can be rewritten as follows, without using integer to pointer cast:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">char</span>* tgt(<span class="dt">char</span>* maybe_underbiased_ptr) { uintptr_t maybe_underbiased_intptr = (uintptr_t)maybe_underbiased_ptr; uintptr_t aligned_biased_intptr = maybe_underbiased_intptr + <span class="dv">15</span>; uintptr_t aligned_intptr = aligned_biased_intptr &amp; (~<span class="dv">15</span>); uintptr_t bias = aligned_intptr - maybe_underbiased_intptr; <span class="kw">return</span> maybe_underbiased_ptr + bias; }</code></pre></div> <p>(Clang-Tidy original name: performance-no-int-to-ptr)</p> + + + + Major + + + + + + + true + false + performance-noexcept-move-constructor + performance + + true + Noexcept Move Constructor + <p>The check flags user-defined move constructors and assignment operators not marked with noexcept or marked with noexcept(expr) where expr evaluates to false (but is not a false literal itself).</p> <p>Move constructors of all the types used with STL containers, for example, need to be declared noexcept. Otherwise STL will choose copy constructors instead. The same is valid for move assignment operations.</p> <p>(Clang-Tidy original name: performance-noexcept-move-constructor)</p> + + + + Major + + + + + + + true + false + performance-trivially-destructible + performance + + true + Trivially Destructible + <p>Finds types that could be made trivially-destructible by removing out-of-line defaulted destructor declarations.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> A: TrivialType { ~A(); <span class="co">// Makes A non-trivially-destructible.</span> TrivialType trivial_fields; }; A::~A() = <span class="kw">default</span>;</code></pre></div> <p>(Clang-Tidy original name: performance-trivially-destructible)</p> + + + + Major + + + + + + + true + false + performance-type-promotion-in-math-fn + performance + + true + Type Promotion In Math Fn + <p>Finds calls to C math library functions (from math.h or, in C++, cmath) with implicit float to double promotions.</p> <p>For example, warns on ::sin(0.f), because this funciton’s parameter is a double. You probably meant to call std::sin(0.f) (in C++), or sinf(0.f) (in C).</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">float</span> a; asin(a); <span class="co">// becomes</span> <span class="dt">float</span> a; std::asin(a);</code></pre></div> <p>(Clang-Tidy original name: performance-type-promotion-in-math-fn)</p> + + + + Major + + + + + + + true + false + performance-unnecessary-copy-initialization + performance + + true + Unnecessary Copy Initialization + <p>Finds local variable declarations that are initialized using the copy constructor of a non-trivially-copyable type but it would suffice to obtain a const reference.</p> <p>The check is only applied if it is safe to replace the copy by a const reference. This is the case when the variable is const qualified or when it is only used as a const, i.e. only const methods or operators are invoked on it, or it is used as const reference or value argument in constructors or function calls.</p> <p>Example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">const</span> string&amp; constReference(); <span class="dt">void</span> Function() { <span class="co">// The warning will suggest making this a const reference.</span> <span class="dt">const</span> string UnnecessaryCopy = constReference(); } <span class="kw">struct</span> Foo { <span class="dt">const</span> string&amp; name() <span class="dt">const</span>; }; <span class="dt">void</span> Function(<span class="dt">const</span> Foo&amp; foo) { <span class="co">// The warning will suggest making this a const reference.</span> string UnnecessaryCopy1 = foo.name(); UnnecessaryCopy1.find(<span class="st">&quot;bar&quot;</span>); <span class="co">// The warning will suggest making this a const reference.</span> string UnnecessaryCopy2 = UnnecessaryCopy1; UnnecessaryCopy2.find(<span class="st">&quot;bar&quot;</span>); }</code></pre></div> <h5 id="options-38">Options</h5> <p>AllowedTypes</p> <p>A semicolon-separated list of names of types allowed to be initialized by copying. Regular expressions are accepted, e.g. [Rr]ef(erence)?$ matches every type with suffix Ref, ref, Reference and reference. The default is empty.</p> <p>(Clang-Tidy original name: performance-unnecessary-copy-initialization)</p> + + + + Major + + + + + + + true + false + performance-unnecessary-value-param + performance + + true + Unnecessary Value Param + <p>Flags value parameter declarations of expensive to copy types that are copied for each invocation but it would suffice to pass them by const reference.</p> <p>The check is only applied to parameters of types that are expensive to copy which means they are not trivially copyable or have a non-trivial copy constructor or destructor.</p> <p>To ensure that it is safe to replace the value parameter with a const reference the following heuristic is employed:</p> <ol style="list-style-type: decimal"> <li>the parameter is const qualified;</li> <li>the parameter is not const, but only const methods or operators are invoked on it, or it is used as const reference or value argument in constructors or function calls.</li> </ol> <p>Example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> f(<span class="dt">const</span> string Value) { <span class="co">// The warning will suggest making Value a reference.</span> } <span class="dt">void</span> g(ExpensiveToCopy Value) { <span class="co">// The warning will suggest making Value a const reference.</span> Value.ConstMethd(); ExpensiveToCopy Copy(Value); }</code></pre></div> <p>If the parameter is not const, only copied or assigned once and has a non-trivial move-constructor or move-assignment operator respectively the check will suggest to move it.</p> <p>Example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> setValue(string Value) { Field = Value; }</code></pre></div> <p>Will become:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#include &lt;utility&gt;</span> <span class="dt">void</span> setValue(string Value) { Field = std::move(Value); }</code></pre></div> <h5 id="options-37">Options</h5> <p>IncludeStyle</p> <p>A string specifying which include-style is used, llvm or google. Default is llvm.</p> <p>AllowedTypes</p> <p>A semicolon-separated list of names of types allowed to be passed by value. Regular expressions are accepted, e.g. [Rr]ef(erence)?$ matches every type with suffix Ref, ref, Reference and reference. The default is empty.</p> <p>(Clang-Tidy original name: performance-unnecessary-value-param)</p> + + + + Major + + + + + + + true + false + portability-restrict-system-includes + portability + + true + Restrict System Includes + <p>Checks to selectively allow or disallow a configurable list of system headers.</p> <p>For example:</p> <p>In order to <strong>only</strong> allow zlib.h from the system you would set the options to -*,zlib.h.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#include &lt;curses.h&gt; </span><span class="co">// Bad: disallowed system header.</span> <span class="ot">#include &lt;openssl/ssl.h&gt; </span><span class="co">// Bad: disallowed system header.</span> <span class="ot">#include &lt;zlib.h&gt; </span><span class="co">// Good: allowed system header.</span> <span class="ot">#include &quot;src/myfile.h&quot; </span><span class="co">// Good: non-system header always allowed.</span></code></pre></div> <p>In order to allow everything <strong>except</strong> zlib.h from the system you would set the options to *,-zlib.h.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#include &lt;curses.h&gt; </span><span class="co">// Good: allowed system header.</span> <span class="ot">#include &lt;openssl/ssl.h&gt; </span><span class="co">// Good: allowed system header.</span> <span class="ot">#include &lt;zlib.h&gt; </span><span class="co">// Bad: disallowed system header.</span> <span class="ot">#include &quot;src/myfile.h&quot; </span><span class="co">// Good: non-system header always allowed.</span></code></pre></div> <p>Since the options support globbing you can use wildcarding to allow groups of headers.</p> <p>-<em>,openssl/</em>.h will allow all openssl headers but disallow any others.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#include &lt;curses.h&gt; </span><span class="co">// Bad: disallowed system header.</span> <span class="ot">#include &lt;openssl/ssl.h&gt; </span><span class="co">// Good: allowed system header.</span> <span class="ot">#include &lt;openssl/rsa.h&gt; </span><span class="co">// Good: allowed system header.</span> <span class="ot">#include &lt;zlib.h&gt; </span><span class="co">// Bad: disallowed system header.</span> <span class="ot">#include &quot;src/myfile.h&quot; </span><span class="co">// Good: non-system header always allowed.</span></code></pre></div> <h5 id="options-35">Options</h5> <p>Includes</p> <p>A string containing a comma separated glob list of allowed include filenames. Similar to the -checks glob list for running clang-tidy itself, the two wildcard characters are * and -, to include and exclude globs, respectively. The default is *, which allows all includes.</p> <p>(Clang-Tidy original name: portability-restrict-system-includes)</p> + + + + Major + + + + + + + true + false + portability-simd-intrinsics + portability + + true + Simd Intrinsics + <p>Finds SIMD intrinsics calls and suggests std::experimental::simd (<a href="https://wg21.link/p0214">P0214</a>) alternatives.</p> <p>If the option <a href="#cmdoption-arg-suggest">Suggest</a> is set to true, for</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">_mm_add_epi32(a, b); <span class="co">// x86</span> vec_add(a, b); <span class="co">// Power</span></code></pre></div> <p>the check suggests an alternative: operator+ on std::experimental::simd objects.</p> <p>Otherwise, it just complains the intrinsics are non-portable (and there are <a href="https://wg21.link/p0214">P0214</a> alternatives).</p> <p>Many architectures provide SIMD operations (e.g. x86 SSE/AVX, Power AltiVec/VSX, ARM NEON). It is common that SIMD code implementing the same algorithm, is written in multiple target-dispatching pieces to optimize for different architectures or micro-architectures.</p> <p>The C++ standard proposal <a href="https://wg21.link/p0214">P0214</a> and its extensions cover many common SIMD operations. By migrating from target-dependent intrinsics to <a href="https://wg21.link/p0214">P0214</a> operations, the SIMD code can be simplified and pieces for different targets can be unified.</p> <p>Refer to <a href="https://wg21.link/p0214">P0214</a> for introduction and motivation for the data-parallel standard library.</p> <h5 id="options-40">Options</h5> <p>Suggest</p> <p>If this option is set to true (default is false), the check will suggest <a href="https://wg21.link/p0214">P0214</a> alternatives, otherwise it only points out the intrinsic function is non-portable.</p> <p>Std</p> <p>The namespace used to suggest <a href="https://wg21.link/p0214">P0214</a> alternatives. If not specified, std:: for -std=c++20 and std::experimental:: for -std=c++11.</p> <p>(Clang-Tidy original name: portability-simd-intrinsics)</p> + + + + Major + + + + + + + true + false + readability-avoid-const-params-in-decls + readability + + true + Avoid Const Params In Decls + <p>Checks whether a function declaration has parameters that are top level const.</p> <p>const values in declarations do not affect the signature of a function, so they should not be put there.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> f(<span class="dt">const</span> string); <span class="co">// Bad: const is top level.</span> <span class="dt">void</span> f(<span class="dt">const</span> string&amp;); <span class="co">// Good: const is not top level.</span></code></pre></div> <p>(Clang-Tidy original name: readability-avoid-const-params-in-decls)</p> + + + + Major + + + + + + + true + false + readability-braces-around-statements + readability + + true + Braces Around Statements + <p>google-readability-braces-around-statements redirects here as an alias for this check.</p> <p>Checks that bodies of if statements and loops (for, do while, and while) are inside braces.</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">if</span> (condition) statement;</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">if</span> (condition) { statement; }</code></pre></div> <h5 id="options-33">Options</h5> <p>ShortStatementLines</p> <p>Defines the minimal number of lines that the statement should have in order to trigger this check.</p> <p>The number of lines is counted from the end of condition or initial keyword (do/else) until the last line of the inner statement. Default value 0 means that braces will be added to all statements (not having them already).</p> <p>(Clang-Tidy original name: readability-braces-around-statements)</p> + + + + Major + + + + + + + true + false + readability-convert-member-functions-to-static + readability + + true + Convert Member Functions To Static + <p>Finds non-static member functions that can be made static because the functions don’t use this.</p> <p>After applying modifications as suggested by the check, running the check again might find more opportunities to mark member functions static.</p> <p>After making a member function static, you might want to run the check <a href="readability-static-accessed-through-instance.html">readability-static-accessed-through-instance</a> to replace calls like Instance.method() by Class::method().</p> <p>(Clang-Tidy original name: readability-convert-member-functions-to-static)</p> + + + + Major + + + + + + + true + false + readability-const-return-type + readability + + true + Const Return Type + <p>Checks for functions with a const-qualified return type and recommends removal of the const keyword. Such use of const is usually superfluous, and can prevent valuable compiler optimizations. Does not (yet) fix trailing return types.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">const</span> <span class="dt">int</span> foo(); <span class="dt">const</span> Clazz foo(); Clazz *<span class="dt">const</span> foo();</code></pre></div> <p>Note that this applies strictly to top-level qualification, which excludes pointers or references to const values. For example, these are fine:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">const</span> <span class="dt">int</span>* foo(); <span class="dt">const</span> <span class="dt">int</span>&amp; foo(); <span class="dt">const</span> Clazz* foo();</code></pre></div> <p>(Clang-Tidy original name: readability-const-return-type)</p> + + + + Major + + + + + + + true + false + readability-container-size-empty + readability + + true + Container Size Empty + <p>Checks whether a call to the size() method can be replaced with a call to empty().</p> <p>The emptiness of a container should be checked using the empty() method instead of the size() method. It is not guaranteed that size() is a constant-time function, and it is generally more efficient and also shows clearer intent to use empty(). Furthermore some containers may implement the empty() method but not implement the size() method. Using empty() whenever possible makes it easier to switch to another container in the future.</p> <p>The check issues warning if a container has size() and empty() methods matching following signatures:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">size_type size() <span class="dt">const</span>; <span class="dt">bool</span> empty() <span class="dt">const</span>;</code></pre></div> <p>size_type can be any kind of integer type.</p> <p>(Clang-Tidy original name: readability-container-size-empty)</p> + + + + Major + + + + + + + true + false + readability-deleted-default + readability + + true + Deleted Default + <p>Checks that constructors and assignment operators marked as = default are not actually deleted by the compiler.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Example { <span class="kw">public</span>: <span class="co">// This constructor is deleted because I is missing a default value.</span> Example() = <span class="kw">default</span>; <span class="co">// This is fine.</span> Example(<span class="dt">const</span> Example&amp; Other) = <span class="kw">default</span>; <span class="co">// This operator is deleted because I cannot be assigned (it is const).</span> Example&amp; <span class="kw">operator</span>=(<span class="dt">const</span> Example&amp; Other) = <span class="kw">default</span>; <span class="kw">private</span>: <span class="dt">const</span> <span class="dt">int</span> I; };</code></pre></div> <p>(Clang-Tidy original name: readability-deleted-default)</p> + + + + Major + + + + + + + true + false + readability-delete-null-pointer + readability + + true + Delete Null Pointer + <p>Checks the if statements where a pointer’s existence is checked and then deletes the pointer. The check is unnecessary as deleting a null pointer has no effect.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> *p; <span class="kw">if</span> (p) <span class="kw">delete</span> p;</code></pre></div> <p>(Clang-Tidy original name: readability-delete-null-pointer)</p> + + + + Major + + + + + + + true + false + readability-else-after-return + readability + + true + Else After Return + <p><a href="https://llvm.org/docs/CodingStandards.html">LLVM Coding Standards</a> advises to reduce indentation where possible and where it makes understanding code easier. Early exit is one of the suggested enforcements of that. Please do not use else or else if after something that interrupts control flow - like return, break, continue, throw.</p> <p>The following piece of code illustrates how the check works. This piece of code:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo(<span class="dt">int</span> Value) { <span class="dt">int</span> Local = <span class="dv">0</span>; <span class="kw">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; <span class="dv">42</span>; i++) { <span class="kw">if</span> (Value == <span class="dv">1</span>) { <span class="kw">return</span>; } <span class="kw">else</span> { Local++; } <span class="kw">if</span> (Value == <span class="dv">2</span>) <span class="kw">continue</span>; <span class="kw">else</span> Local++; <span class="kw">if</span> (Value == <span class="dv">3</span>) { <span class="kw">throw</span> <span class="dv">42</span>; } <span class="kw">else</span> { Local++; } } }</code></pre></div> <p>Would be transformed into:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo(<span class="dt">int</span> Value) { <span class="dt">int</span> Local = <span class="dv">0</span>; <span class="kw">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; <span class="dv">42</span>; i++) { <span class="kw">if</span> (Value == <span class="dv">1</span>) { <span class="kw">return</span>; } Local++; <span class="kw">if</span> (Value == <span class="dv">2</span>) <span class="kw">continue</span>; Local++; <span class="kw">if</span> (Value == <span class="dv">3</span>) { <span class="kw">throw</span> <span class="dv">42</span>; } Local++; } }</code></pre></div> <h5 id="options-75">Options</h5> <p>WarnOnUnfixable</p> <p>When true, emit a warning for cases where the check can’t output a Fix-It. These can occur with declarations inside the else branch that would have an extended lifetime if the else branch was removed. Default value is true.</p> <p>WarnOnConditionVariables</p> <p>When true, the check will attempt to refactor a variable defined inside the condition of the if statement that is used in the else branch defining them just before the if statement. This can only be done if the if statement is the last statement in its parents scope. Default value is true.</p> <h5 id="llvm-alias">LLVM alias</h5> <p>There is an alias of this check called llvm-else-after-return. In that version the options <a href="#cmdoption-arg-warnonunfixable">WarnOnUnfixable</a> and <a href="#cmdoption-arg-warnonconditionvariables">WarnOnConditionVariables</a> are both set to false by default.</p> <p>This check helps to enforce this <a href="https://llvm.org/docs/CodingStandards.html#don-t-use-else-after-a-return">LLVM Coding Standards recommendation</a>.</p> <p>(Clang-Tidy original name: readability-else-after-return)</p> + + + + Major + + + + + + + true + false + readability-function-cognitive-complexity + readability + + true + Function Cognitive Complexity + <p>Checks function Cognitive Complexity metric.</p> <p>The metric is implemented as per the <a href="https://www.sonarsource.com/docs/CognitiveComplexity.pdf">COGNITIVE COMPLEXITY by SonarSource</a> specification version 1.2 (19 April 2017).</p> <h5 id="options-1">Options</h5> <p>Threshold</p> <p>Flag functions with Cognitive Complexity exceeding this number. The default is 25.</p> <h5 id="building-blocks">Building blocks</h5> <p>There are three basic building blocks of a Cognitive Complexity metric:</p> <h6 id="increment">Increment</h6> <p>The following structures increase the function’s Cognitive Complexity metric (by 1):</p> <ul> <li><p>Conditional operators:</p> <ul> <li>if()</li> <li>else if()</li> <li>else</li> <li>cond ? true : false</li> </ul></li> <li><p>switch()</p></li> <li><p>Loops:</p> <ul> <li>for()</li> <li>C++11 range-based for()</li> <li>while()</li> <li>do while()</li> </ul></li> <li><p>catch ()</p></li> <li><p>goto LABEL, goto *(&amp;&amp;LABEL)),</p></li> <li><p>sequences of binary logical operators:</p> <ul> <li>boolean1 || boolean2</li> <li>boolean1 &amp;&amp; boolean2</li> </ul></li> </ul> <h6 id="nesting-level">Nesting level</h6> <p>While by itself the nesting level not change the function’s Cognitive Complexity metric, it is tracked, and is used by the next, third building block. The following structures increase the nesting level (by 1):</p> <ul> <li><p>Conditional operators:</p> <ul> <li>if()</li> <li>else if()</li> <li>else</li> <li>cond ? true : false</li> </ul></li> <li><p>switch()</p></li> <li><p>Loops:</p> <ul> <li>for()</li> <li>C++11 range-based for()</li> <li>while()</li> <li>do while()</li> </ul></li> <li><p>catch ()</p></li> <li><p>Nested functions:</p> <ul> <li>C++11 Lambda</li> <li>Nested class</li> <li>Nested struct</li> </ul></li> <li><p>GNU statement expression</p></li> <li><p>Apple Block Declaration</p></li> </ul> <h6 id="nesting-increment">Nesting increment</h6> <p>This is where the previous basic building block, <a href="#nesting-level">Nesting level</a>, matters. The following structures increase the function’s Cognitive Complexity metric by the current <a href="#nesting-level">Nesting level</a>:</p> <ul> <li><p>Conditional operators:</p> <ul> <li>if()</li> <li>cond ? true : false</li> </ul></li> <li><p>switch()</p></li> <li><p>Loops:</p> <ul> <li>for()</li> <li>C++11 range-based for()</li> <li>while()</li> <li>do while()</li> </ul></li> <li><p>catch ()</p></li> </ul> <h5 id="examples">Examples</h5> <p>The simplest case. This function has Cognitive Complexity of 0.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> function0() {}</code></pre></div> <p>Slightly better example. This function has Cognitive Complexity of 1.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> function1(<span class="dt">bool</span> var) { <span class="kw">if</span>(var) <span class="co">// +1, nesting level +1</span> <span class="kw">return</span> <span class="dv">42</span>; <span class="kw">return</span> <span class="dv">0</span>; }</code></pre></div> <p>Full example. This function has Cognitive Complexity of 3.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> function3(<span class="dt">bool</span> var1, <span class="dt">bool</span> var2) { <span class="kw">if</span>(var1) { <span class="co">// +1, nesting level +1</span> <span class="kw">if</span>(var2) <span class="co">// +2 (1 + current nesting level of 1), nesting level +1</span> <span class="kw">return</span> <span class="dv">42</span>; } <span class="kw">return</span> <span class="dv">0</span>; }</code></pre></div> <h5 id="limitations">Limitations</h5> <p>The metric is implemented with two notable exceptions:</p> <ul> <li>preprocessor conditionals (#ifdef, #if, #elif, #else, #endif) are not accounted for.</li> <li>each method in a recursion cycle is not accounted for. It can’t be fully implemented, because cross-translational-unit analysis would be needed, which is currently not possible in clang-tidy.</li> </ul> <p>(Clang-Tidy original name: readability-function-cognitive-complexity)</p> + + + + Major + + + + + + + true + false + readability-function-size + readability + + true + Function Size + <p>google-readability-function-size redirects here as an alias for this check.</p> <p>Checks for large functions based on various metrics.</p> <h5 id="options-31">Options</h5> <p>LineThreshold</p> <p>Flag functions exceeding this number of lines. The default is -1 (ignore the number of lines).</p> <p>StatementThreshold</p> <p>Flag functions exceeding this number of statements. This may differ significantly from the number of lines for macro-heavy code. The default is 800.</p> <p>BranchThreshold</p> <p>Flag functions exceeding this number of control statements. The default is -1 (ignore the number of branches).</p> <p>ParameterThreshold</p> <p>Flag functions that exceed a specified number of parameters. The default is -1 (ignore the number of parameters).</p> <p>NestingThreshold</p> <p>Flag compound statements which create next nesting level after NestingThreshold. This may differ significantly from the expected value for macro-heavy code. The default is -1 (ignore the nesting level).</p> <p>VariableThreshold</p> <p>Flag functions exceeding this number of variables declared in the body. The default is -1 (ignore the number of variables). Please note that function parameters and variables declared in lambdas, GNU Statement Expressions, and nested class inline functions are not counted.</p> <p>(Clang-Tidy original name: readability-function-size)</p> + + + + Major + + + + + + + true + false + readability-implicit-bool-conversion + readability + + true + Implicit Bool Conversion + <p>This check can be used to find implicit conversions between built-in types and booleans. Depending on use case, it may simply help with readability of the code, or in some cases, point to potential bugs which remain unnoticed due to implicit conversions.</p> <p>The following is a real-world example of bug which was hiding behind implicit bool conversion:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="dt">int</span> m_foo; <span class="kw">public</span>: <span class="dt">void</span> setFoo(<span class="dt">bool</span> foo) { m_foo = foo; } <span class="co">// warning: implicit conversion bool -&gt; int</span> <span class="dt">int</span> getFoo() { <span class="kw">return</span> m_foo; } }; <span class="dt">void</span> use(Foo&amp; foo) { <span class="dt">bool</span> value = foo.getFoo(); <span class="co">// warning: implicit conversion int -&gt; bool</span> }</code></pre></div> <p>This code is the result of unsuccessful refactoring, where type of m_foo changed from bool to int. The programmer forgot to change all occurrences of bool, and the remaining code is no longer correct, yet it still compiles without any visible warnings.</p> <p>In addition to issuing warnings, fix-it hints are provided to help solve the reported issues. This can be used for improving readability of code, for example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> conversionsToBool() { <span class="dt">float</span> floating; <span class="dt">bool</span> boolean = floating; <span class="co">// ^ propose replacement: bool boolean = floating != 0.0f;</span> <span class="dt">int</span> integer; <span class="kw">if</span> (integer) {} <span class="co">// ^ propose replacement: if (integer != 0) {}</span> <span class="dt">int</span>* pointer; <span class="kw">if</span> (!pointer) {} <span class="co">// ^ propose replacement: if (pointer == nullptr) {}</span> <span class="kw">while</span> (<span class="dv">1</span>) {} <span class="co">// ^ propose replacement: while (true) {}</span> } <span class="dt">void</span> functionTakingInt(<span class="dt">int</span> param); <span class="dt">void</span> conversionsFromBool() { <span class="dt">bool</span> boolean; functionTakingInt(boolean); <span class="co">// ^ propose replacement: functionTakingInt(static_cast&lt;int&gt;(boolean));</span> functionTakingInt(<span class="kw">true</span>); <span class="co">// ^ propose replacement: functionTakingInt(1);</span> }</code></pre></div> <p>In general, the following conversion types are checked:</p> <ul> <li>integer expression/literal to boolean (conversion from a single bit bitfield to boolean is explicitly allowed, since there’s no ambiguity / information loss in this case),</li> <li>floating expression/literal to boolean,</li> <li>pointer/pointer to member/nullptr/NULL to boolean,</li> <li>boolean expression/literal to integer (conversion from boolean to a single bit bitfield is explicitly allowed),</li> <li>boolean expression/literal to floating.</li> </ul> <p>The rules for generating fix-it hints are:</p> <ul> <li>in case of conversions from other built-in type to bool, an explicit comparison is proposed to make it clear what exactly is being compared: <ul> <li>bool boolean = floating; is changed to bool boolean = floating == 0.0f;,</li> <li>for other types, appropriate literals are used (0, 0u, 0.0f, 0.0, nullptr),</li> </ul></li> <li>in case of negated expressions conversion to bool, the proposed replacement with comparison is simplified: <ul> <li>if (!pointer) is changed to if (pointer == nullptr),</li> </ul></li> <li>in case of conversions from bool to other built-in types, an explicit static_cast is proposed to make it clear that a conversion is taking place: <ul> <li>int integer = boolean; is changed to int integer = static_cast<int>(boolean);,</li> </ul></li> <li>if the conversion is performed on type literals, an equivalent literal is proposed, according to what type is actually expected, for example: <ul> <li>functionTakingBool(0); is changed to functionTakingBool(false);,</li> <li>functionTakingInt(true); is changed to functionTakingInt(1);,</li> <li>for other types, appropriate literals are used (false, true, 0, 1, 0u, 1u, 0.0f, 1.0f, 0.0, 1.0f).</li> </ul></li> </ul> <p>Some additional accommodations are made for pre-C++11 dialects:</p> <ul> <li>false literal conversion to pointer is detected,</li> <li>instead of nullptr literal, 0 is proposed as replacement.</li> </ul> <p>Occurrences of implicit conversions inside macros and template instantiations are deliberately ignored, as it is not clear how to deal with such cases.</p> <h5 id="options-17">Options</h5> <p>AllowIntegerConditions</p> <p>When true, the check will allow conditional integer conversions. Default is false.</p> <p>AllowPointerConditions</p> <p>When true, the check will allow conditional pointer conversions. Default is false.</p> <p>(Clang-Tidy original name: readability-implicit-bool-conversion)</p> + + + + Major + + + + + + + true + false + readability-isolate-declaration + readability + + true + Isolate Declaration + <p>Detects local variable declarations declaring more than one variable and tries to refactor the code to one statement per declaration.</p> <p>The automatic code-transformation will use the same indentation as the original for every created statement and add a line break after each statement. It keeps the order of the variable declarations consistent, too.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> f() { <span class="dt">int</span> * pointer = <span class="kw">nullptr</span>, value = <span class="dv">42</span>, * <span class="dt">const</span> const_ptr = &amp;value; <span class="co">// This declaration will be diagnosed and transformed into:</span> <span class="co">// int * pointer = nullptr;</span> <span class="co">// int value = 42;</span> <span class="co">// int * const const_ptr = &amp;value;</span> }</code></pre></div> <p>The check excludes places where it is necessary or common to declare multiple variables in one statement and there is no other way supported in the language. Please note that structured bindings are not considered.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// It is not possible to transform this declaration and doing the declaration</span> <span class="co">// before the loop will increase the scope of the variable &#39;Begin&#39; and &#39;End&#39;</span> <span class="co">// which is undesirable.</span> <span class="kw">for</span> (<span class="dt">int</span> Begin = <span class="dv">0</span>, End = <span class="dv">100</span>; Begin &lt; End; ++Begin); <span class="kw">if</span> (<span class="dt">int</span> Begin = <span class="dv">42</span>, Result = some_function(Begin); Begin == Result); <span class="co">// It is not possible to transform this declaration because the result is</span> <span class="co">// not functionality preserving as &#39;j&#39; and &#39;k&#39; would not be part of the</span> <span class="co">// &#39;if&#39; statement anymore.</span> <span class="kw">if</span> (SomeCondition()) <span class="dt">int</span> i = <span class="dv">42</span>, j = <span class="dv">43</span>, k = function(i,j);</code></pre></div> <h5 id="limitations-2">Limitations</h5> <p>Global variables and member variables are excluded.</p> <p>The check currently does not support the automatic transformation of member-pointer-types.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> S { <span class="dt">int</span> a; <span class="dt">const</span> <span class="dt">int</span> b; <span class="dt">void</span> f() {} }; <span class="dt">void</span> f() { <span class="co">// Only a diagnostic message is emitted</span> <span class="dt">int</span> S::*p = &amp;S::a, S::*<span class="dt">const</span> q = &amp;S::a; }</code></pre></div> <p>Furthermore, the transformation is very cautious when it detects various kinds of macros or preprocessor directives in the range of the statement. In this case the transformation will not happen to avoid unexpected side-effects due to macros.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#define NULL 0</span> <span class="ot">#define MY_NICE_TYPE int **</span> <span class="ot">#define VAR_NAME(name) name##__LINE__</span> <span class="ot">#define A_BUNCH_OF_VARIABLES int m1 = 42, m2 = 43, m3 = 44;</span> <span class="dt">void</span> macros() { <span class="dt">int</span> *p1 = NULL, *p2 = NULL; <span class="co">// Will be transformed to</span> <span class="co">// int *p1 = NULL;</span> <span class="co">// int *p2 = NULL;</span> MY_NICE_TYPE p3, v1, v2; <span class="co">// Won&#39;t be transformed, but a diagnostic is emitted.</span> <span class="dt">int</span> VAR_NAME(v3), VAR_NAME(v4), VAR_NAME(v5); <span class="co">// Won&#39;t be transformed, but a diagnostic is emitted.</span> A_BUNCH_OF_VARIABLES <span class="co">// Won&#39;t be transformed, but a diagnostic is emitted.</span> <span class="dt">int</span> Unconditional, <span class="ot">#if CONFIGURATION</span> IfConfigured = <span class="dv">42</span>, <span class="ot">#else</span> IfConfigured = <span class="dv">0</span>; <span class="ot">#endif</span> <span class="co">// Won&#39;t be transformed, but a diagnostic is emitted.</span> }</code></pre></div> <p>(Clang-Tidy original name: readability-isolate-declaration)</p> + + + + Major + + + + + + + true + false + readability-inconsistent-declaration-parameter-name + readability + + true + Inconsistent Declaration Parameter Name + <p>Find function declarations which differ in parameter names.</p> <p>Example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// in foo.hpp:</span> <span class="dt">void</span> foo(<span class="dt">int</span> a, <span class="dt">int</span> b, <span class="dt">int</span> c); <span class="co">// in foo.cpp:</span> <span class="dt">void</span> foo(<span class="dt">int</span> d, <span class="dt">int</span> e, <span class="dt">int</span> f); <span class="co">// warning</span></code></pre></div> <p>This check should help to enforce consistency in large projects, where it often happens that a definition of function is refactored, changing the parameter names, but its declaration in header file is not updated. With this check, we can easily find and correct such inconsistencies, keeping declaration and definition always in sync.</p> <p>Unnamed parameters are allowed and are not taken into account when comparing function declarations, for example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo(<span class="dt">int</span> a); <span class="dt">void</span> foo(<span class="dt">int</span>); <span class="co">// no warning</span></code></pre></div> <p>One name is also allowed to be a case-insensitive prefix/suffix of the other:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo(<span class="dt">int</span> count); <span class="dt">void</span> foo(<span class="dt">int</span> count_input) { <span class="co">// no warning</span> <span class="dt">int</span> count = adjustCount(count_input); }</code></pre></div> <p>To help with refactoring, in some cases fix-it hints are generated to align parameter names to a single naming convention. This works with the assumption that the function definition is the most up-to-date version, as it directly references parameter names in its body. Example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo(<span class="dt">int</span> a); <span class="co">// warning and fix-it hint (replace &quot;a&quot; to &quot;b&quot;)</span> <span class="dt">int</span> foo(<span class="dt">int</span> b) { <span class="kw">return</span> b + <span class="dv">2</span>; } <span class="co">// definition with use of &quot;b&quot;</span></code></pre></div> <p>In the case of multiple redeclarations or function template specializations, a warning is issued for every redeclaration or specialization inconsistent with the definition or the first declaration seen in a translation unit.</p> <p>IgnoreMacros</p> <p>If this option is set to true (default is true), the check will not warn about names declared inside macros.</p> <p>Strict</p> <p>If this option is set to true (default is false), then names must match exactly (or be absent).</p> <p>(Clang-Tidy original name: readability-inconsistent-declaration-parameter-name)</p> + + + + Major + + + + + + + true + false + readability-identifier-naming + readability + + true + Identifier Naming + <p>Checks for identifiers naming style mismatch.</p> <p>This check will try to enforce coding guidelines on the identifiers naming. It supports one of the following casing types and tries to convert from one to another if a mismatch is detected</p> <p>Casing types include:</p> <ul> <li>lower_case,</li> <li>UPPER_CASE,</li> <li>camelBack,</li> <li>CamelCase,</li> <li>camel_Snake_Back,</li> <li>Camel_Snake_Case,</li> <li>aNy_CasE.</li> </ul> <p>It also supports a fixed prefix and suffix that will be prepended or appended to the identifiers, regardless of the casing.</p> <p>Many configuration options are available, in order to be able to create different rules for different kinds of identifiers. In general, the rules are falling back to a more generic rule if the specific case is not configured.</p> <p>The naming of virtual methods is reported where they occur in the base class, but not where they are overridden, as it can’t be fixed locally there. This also applies for pseudo-override patterns like CRTP.</p> <h5 id="options-27">Options</h5> <p>The following options are describe below:</p> <ul> <li><a href="#cmdoption-arg-abstractclasscase">AbstractClassCase</a>, <a href="#cmdoption-arg-abstractclassprefix">AbstractClassPrefix</a>, <a href="#cmdoption-arg-abstractclasssuffix">AbstractClassSuffix</a>, <a href="#cmdoption-arg-abstractclassignoredregexp">AbstractClassIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-aggressivedependentmemberlookup">AggressiveDependentMemberLookup</a></li> <li><a href="#cmdoption-arg-classcase">ClassCase</a>, <a href="#cmdoption-arg-classprefix">ClassPrefix</a>, <a href="#cmdoption-arg-classsuffix">ClassSuffix</a>, <a href="#cmdoption-arg-classignoredregexp">ClassIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-classconstantcase">ClassConstantCase</a>, <a href="#cmdoption-arg-classconstantprefix">ClassConstantPrefix</a>, <a href="#cmdoption-arg-classconstantsuffix">ClassConstantSuffix</a>, <a href="#cmdoption-arg-classconstantignoredregexp">ClassConstantIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-classmembercase">ClassMemberCase</a>, <a href="#cmdoption-arg-classmemberprefix">ClassMemberPrefix</a>, <a href="#cmdoption-arg-classmembersuffix">ClassMemberSuffix</a>, <a href="#cmdoption-arg-classmemberignoredregexp">ClassMemberIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-classmethodcase">ClassMethodCase</a>, <a href="#cmdoption-arg-classmethodprefix">ClassMethodPrefix</a>, <a href="#cmdoption-arg-classmethodsuffix">ClassMethodSuffix</a>, <a href="#cmdoption-arg-classmethodignoredregexp">ClassMethodIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-constantcase">ConstantCase</a>, <a href="#cmdoption-arg-constantprefix">ConstantPrefix</a>, <a href="#cmdoption-arg-constantsuffix">ConstantSuffix</a>, <a href="#cmdoption-arg-constantignoredregexp">ConstantIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-constantmembercase">ConstantMemberCase</a>, <a href="#cmdoption-arg-constantmemberprefix">ConstantMemberPrefix</a>, <a href="#cmdoption-arg-constantmembersuffix">ConstantMemberSuffix</a>, <a href="#cmdoption-arg-constantmemberignoredregexp">ConstantMemberIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-constantparametercase">ConstantParameterCase</a>, <a href="#cmdoption-arg-constantparameterprefix">ConstantParameterPrefix</a>, <a href="#cmdoption-arg-constantparametersuffix">ConstantParameterSuffix</a>, <a href="#cmdoption-arg-constantparameterignoredregexp">ConstantParameterIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-constantpointerparametercase">ConstantPointerParameterCase</a>, <a href="#cmdoption-arg-constantpointerparameterprefix">ConstantPointerParameterPrefix</a>, <a href="#cmdoption-arg-constantpointerparametersuffix">ConstantPointerParameterSuffix</a>, <a href="#cmdoption-arg-constantpointerparameterignoredregexp">ConstantPointerParameterIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-constexprfunctioncase">ConstexprFunctionCase</a>, <a href="#cmdoption-arg-constexprfunctionprefix">ConstexprFunctionPrefix</a>, <a href="#cmdoption-arg-constexprfunctionsuffix">ConstexprFunctionSuffix</a>, <a href="#cmdoption-arg-constexprfunctionignoredregexp">ConstexprFunctionIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-constexprmethodcase">ConstexprMethodCase</a>, <a href="#cmdoption-arg-constexprmethodprefix">ConstexprMethodPrefix</a>, <a href="#cmdoption-arg-constexprmethodsuffix">ConstexprMethodSuffix</a>, <a href="#cmdoption-arg-constexprmethodignoredregexp">ConstexprMethodIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-constexprvariablecase">ConstexprVariableCase</a>, <a href="#cmdoption-arg-constexprvariableprefix">ConstexprVariablePrefix</a>, <a href="#cmdoption-arg-constexprvariablesuffix">ConstexprVariableSuffix</a>, <a href="#cmdoption-arg-constexprvariableignoredregexp">ConstexprVariableIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-enumcase">EnumCase</a>, <a href="#cmdoption-arg-enumprefix">EnumPrefix</a>, <a href="#cmdoption-arg-enumsuffix">EnumSuffix</a>, <a href="#cmdoption-arg-enumignoredregexp">EnumIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-enumconstantcase">EnumConstantCase</a>, <a href="#cmdoption-arg-enumconstantprefix">EnumConstantPrefix</a>, <a href="#cmdoption-arg-enumconstantsuffix">EnumConstantSuffix</a>, <a href="#cmdoption-arg-enumconstantignoredregexp">EnumConstantIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-functioncase">FunctionCase</a>, <a href="#cmdoption-arg-functionprefix">FunctionPrefix</a>, <a href="#cmdoption-arg-functionsuffix">FunctionSuffix</a>, <a href="#cmdoption-arg-functionignoredregexp">FunctionIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-getconfigperfile">GetConfigPerFile</a></li> <li><a href="#cmdoption-arg-globalconstantcase">GlobalConstantCase</a>, <a href="#cmdoption-arg-globalconstantprefix">GlobalConstantPrefix</a>, <a href="#cmdoption-arg-globalconstantsuffix">GlobalConstantSuffix</a>, <a href="#cmdoption-arg-globalconstantignoredregexp">GlobalConstantIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-globalconstantpointercase">GlobalConstantPointerCase</a>, <a href="#cmdoption-arg-globalconstantpointerprefix">GlobalConstantPointerPrefix</a>, <a href="#cmdoption-arg-globalconstantpointersuffix">GlobalConstantPointerSuffix</a>, <a href="#cmdoption-arg-globalconstantpointerignoredregexp">GlobalConstantPointerIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-globalfunctioncase">GlobalFunctionCase</a>, <a href="#cmdoption-arg-globalfunctionprefix">GlobalFunctionPrefix</a>, <a href="#cmdoption-arg-globalfunctionsuffix">GlobalFunctionSuffix</a>, <a href="#cmdoption-arg-globalfunctionignoredregexp">GlobalFunctionIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-globalpointercase">GlobalPointerCase</a>, <a href="#cmdoption-arg-globalpointerprefix">GlobalPointerPrefix</a>, <a href="#cmdoption-arg-globalpointersuffix">GlobalPointerSuffix</a>, <a href="#cmdoption-arg-globalpointerignoredregexp">GlobalPointerIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-globalvariablecase">GlobalVariableCase</a>, <a href="#cmdoption-arg-globalvariableprefix">GlobalVariablePrefix</a>, <a href="#cmdoption-arg-globalvariablesuffix">GlobalVariableSuffix</a>, <a href="#cmdoption-arg-globalvariableignoredregexp">GlobalVariableIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-ignoremainlikefunctions">IgnoreMainLikeFunctions</a></li> <li><a href="#cmdoption-arg-inlinenamespacecase">InlineNamespaceCase</a>, <a href="#cmdoption-arg-inlinenamespaceprefix">InlineNamespacePrefix</a>, <a href="#cmdoption-arg-inlinenamespacesuffix">InlineNamespaceSuffix</a>, <a href="#cmdoption-arg-inlinenamespaceignoredregexp">InlineNamespaceIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-localconstantcase">LocalConstantCase</a>, <a href="#cmdoption-arg-localconstantprefix">LocalConstantPrefix</a>, <a href="#cmdoption-arg-localconstantsuffix">LocalConstantSuffix</a>, <a href="#cmdoption-arg-localconstantignoredregexp">LocalConstantIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-localconstantpointercase">LocalConstantPointerCase</a>, <a href="#cmdoption-arg-localconstantpointerprefix">LocalConstantPointerPrefix</a>, <a href="#cmdoption-arg-localconstantpointersuffix">LocalConstantPointerSuffix</a>, <a href="#cmdoption-arg-localconstantpointerignoredregexp">LocalConstantPointerIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-localpointercase">LocalPointerCase</a>, <a href="#cmdoption-arg-localpointerprefix">LocalPointerPrefix</a>, <a href="#cmdoption-arg-localpointersuffix">LocalPointerSuffix</a>, <a href="#cmdoption-arg-localpointerignoredregexp">LocalPointerIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-localvariablecase">LocalVariableCase</a>, <a href="#cmdoption-arg-localvariableprefix">LocalVariablePrefix</a>, <a href="#cmdoption-arg-localvariablesuffix">LocalVariableSuffix</a>, <a href="#cmdoption-arg-localvariableignoredregexp">LocalVariableIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-macrodefinitioncase">MacroDefinitionCase</a>, <a href="#cmdoption-arg-macrodefinitionprefix">MacroDefinitionPrefix</a>, <a href="#cmdoption-arg-macrodefinitionsuffix">MacroDefinitionSuffix</a>, <a href="#cmdoption-arg-macrodefinitionignoredregexp">MacroDefinitionIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-membercase">MemberCase</a>, <a href="#cmdoption-arg-memberprefix">MemberPrefix</a>, <a href="#cmdoption-arg-membersuffix">MemberSuffix</a>, <a href="#cmdoption-arg-memberignoredregexp">MemberIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-methodcase">MethodCase</a>, <a href="#cmdoption-arg-methodprefix">MethodPrefix</a>, <a href="#cmdoption-arg-methodsuffix">MethodSuffix</a>, <a href="#cmdoption-arg-methodignoredregexp">MethodIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-namespacecase">NamespaceCase</a>, <a href="#cmdoption-arg-namespaceprefix">NamespacePrefix</a>, <a href="#cmdoption-arg-namespacesuffix">NamespaceSuffix</a>, <a href="#cmdoption-arg-namespaceignoredregexp">NamespaceIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-parametercase">ParameterCase</a>, <a href="#cmdoption-arg-parameterprefix">ParameterPrefix</a>, <a href="#cmdoption-arg-parametersuffix">ParameterSuffix</a>, <a href="#cmdoption-arg-parameterignoredregexp">ParameterIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-parameterpackcase">ParameterPackCase</a>, <a href="#cmdoption-arg-parameterpackprefix">ParameterPackPrefix</a>, <a href="#cmdoption-arg-parameterpacksuffix">ParameterPackSuffix</a>, <a href="#cmdoption-arg-parameterpackignoredregexp">ParameterPackIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-pointerparametercase">PointerParameterCase</a>, <a href="#cmdoption-arg-pointerparameterprefix">PointerParameterPrefix</a>, <a href="#cmdoption-arg-pointerparametersuffix">PointerParameterSuffix</a>, <a href="#cmdoption-arg-pointerparameterignoredregexp">PointerParameterIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-privatemembercase">PrivateMemberCase</a>, <a href="#cmdoption-arg-privatememberprefix">PrivateMemberPrefix</a>, <a href="#cmdoption-arg-privatemembersuffix">PrivateMemberSuffix</a>, <a href="#cmdoption-arg-privatememberignoredregexp">PrivateMemberIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-privatemethodcase">PrivateMethodCase</a>, <a href="#cmdoption-arg-privatemethodprefix">PrivateMethodPrefix</a>, <a href="#cmdoption-arg-privatemethodsuffix">PrivateMethodSuffix</a>, <a href="#cmdoption-arg-privatemethodignoredregexp">PrivateMethodIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-protectedmembercase">ProtectedMemberCase</a>, <a href="#cmdoption-arg-protectedmemberprefix">ProtectedMemberPrefix</a>, <a href="#cmdoption-arg-protectedmembersuffix">ProtectedMemberSuffix</a>, <a href="#cmdoption-arg-protectedmemberignoredregexp">ProtectedMemberIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-protectedmethodcase">ProtectedMethodCase</a>, <a href="#cmdoption-arg-protectedmethodprefix">ProtectedMethodPrefix</a>, <a href="#cmdoption-arg-protectedmethodsuffix">ProtectedMethodSuffix</a>, <a href="#cmdoption-arg-protectedmethodignoredregexp">ProtectedMethodIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-publicmembercase">PublicMemberCase</a>, <a href="#cmdoption-arg-publicmemberprefix">PublicMemberPrefix</a>, <a href="#cmdoption-arg-publicmembersuffix">PublicMemberSuffix</a>, <a href="#cmdoption-arg-publicmemberignoredregexp">PublicMemberIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-publicmethodcase">PublicMethodCase</a>, <a href="#cmdoption-arg-publicmethodprefix">PublicMethodPrefix</a>, <a href="#cmdoption-arg-publicmethodsuffix">PublicMethodSuffix</a>, <a href="#cmdoption-arg-publicmethodignoredregexp">PublicMethodIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-scopedenumconstantcase">ScopedEnumConstantCase</a>, <a href="#cmdoption-arg-scopedenumconstantprefix">ScopedEnumConstantPrefix</a>, <a href="#cmdoption-arg-scopedenumconstantsuffix">ScopedEnumConstantSuffix</a>, <a href="#cmdoption-arg-scopedenumconstantignoredregexp">ScopedEnumConstantIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-staticconstantcase">StaticConstantCase</a>, <a href="#cmdoption-arg-staticconstantprefix">StaticConstantPrefix</a>, <a href="#cmdoption-arg-staticconstantsuffix">StaticConstantSuffix</a>, <a href="#cmdoption-arg-staticconstantignoredregexp">StaticConstantIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-staticvariablecase">StaticVariableCase</a>, <a href="#cmdoption-arg-staticvariableprefix">StaticVariablePrefix</a>, <a href="#cmdoption-arg-staticvariablesuffix">StaticVariableSuffix</a>, <a href="#cmdoption-arg-staticvariableignoredregexp">StaticVariableIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-structcase">StructCase</a>, <a href="#cmdoption-arg-structprefix">StructPrefix</a>, <a href="#cmdoption-arg-structsuffix">StructSuffix</a>, <a href="#cmdoption-arg-structignoredregexp">StructIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-templateparametercase">TemplateParameterCase</a>, <a href="#cmdoption-arg-templateparameterprefix">TemplateParameterPrefix</a>, <a href="#cmdoption-arg-templateparametersuffix">TemplateParameterSuffix</a>, <a href="#cmdoption-arg-templateparameterignoredregexp">TemplateParameterIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-templatetemplateparametercase">TemplateTemplateParameterCase</a>, <a href="#cmdoption-arg-templatetemplateparameterprefix">TemplateTemplateParameterPrefix</a>, <a href="#cmdoption-arg-templatetemplateparametersuffix">TemplateTemplateParameterSuffix</a>, <a href="#cmdoption-arg-templatetemplateparameterignoredregexp">TemplateTemplateParameterIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-typealiascase">TypeAliasCase</a>, <a href="#cmdoption-arg-typealiasprefix">TypeAliasPrefix</a>, <a href="#cmdoption-arg-typealiassuffix">TypeAliasSuffix</a>, <a href="#cmdoption-arg-typealiasignoredregexp">TypeAliasIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-typedefcase">TypedefCase</a>, <a href="#cmdoption-arg-typedefprefix">TypedefPrefix</a>, <a href="#cmdoption-arg-typedefsuffix">TypedefSuffix</a>, <a href="#cmdoption-arg-typedefignoredregexp">TypedefIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-typetemplateparametercase">TypeTemplateParameterCase</a>, <a href="#cmdoption-arg-typetemplateparameterprefix">TypeTemplateParameterPrefix</a>, <a href="#cmdoption-arg-typetemplateparametersuffix">TypeTemplateParameterSuffix</a>, <a href="#cmdoption-arg-typetemplateparameterignoredregexp">TypeTemplateParameterIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-unioncase">UnionCase</a>, <a href="#cmdoption-arg-unionprefix">UnionPrefix</a>, <a href="#cmdoption-arg-unionsuffix">UnionSuffix</a>, <a href="#cmdoption-arg-unionignoredregexp">UnionIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-valuetemplateparametercase">ValueTemplateParameterCase</a>, <a href="#cmdoption-arg-valuetemplateparameterprefix">ValueTemplateParameterPrefix</a>, <a href="#cmdoption-arg-valuetemplateparametersuffix">ValueTemplateParameterSuffix</a>, <a href="#cmdoption-arg-valuetemplateparameterignoredregexp">ValueTemplateParameterIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-variablecase">VariableCase</a>, <a href="#cmdoption-arg-variableprefix">VariablePrefix</a>, <a href="#cmdoption-arg-variablesuffix">VariableSuffix</a>, <a href="#cmdoption-arg-variableignoredregexp">VariableIgnoredRegexp</a></li> <li><a href="#cmdoption-arg-virtualmethodcase">VirtualMethodCase</a>, <a href="#cmdoption-arg-virtualmethodprefix">VirtualMethodPrefix</a>, <a href="#cmdoption-arg-virtualmethodsuffix">VirtualMethodSuffix</a>, <a href="#cmdoption-arg-virtualmethodignoredregexp">VirtualMethodIgnoredRegexp</a></li> </ul> <p>AbstractClassCase</p> <p>When defined, the check will ensure abstract class names conform to the selected casing.</p> <p>AbstractClassPrefix</p> <p>When defined, the check will ensure abstract class names will add the prefixed with the given value (regardless of casing).</p> <p>AbstractClassIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for abstract class names matching this regular expression.</p> <p>AbstractClassSuffix</p> <p>When defined, the check will ensure abstract class names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>AbstractClassCase of lower_case</li> <li>AbstractClassPrefix of pre_</li> <li>AbstractClassSuffix of _post</li> </ul> <p>Identifies and/or transforms abstract class names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> ABSTRACT_CLASS { <span class="kw">public</span>: ABSTRACT_CLASS(); };</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> pre_abstract_class_post { <span class="kw">public</span>: pre_abstract_class_post(); };</code></pre></div> <p>AggressiveDependentMemberLookup</p> <p>When set to true the check will look in dependent base classes for dependent member references that need changing. This can lead to errors with template specializations so the default value is false.</p> <p>For example using values of:</p> <ul> <li>ClassMemberCase of lower_case</li> </ul> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">template</span> &lt;<span class="kw">typename</span> T&gt; <span class="kw">struct</span> Base { T BadNamedMember; }; <span class="kw">template</span> &lt;<span class="kw">typename</span> T&gt; <span class="kw">struct</span> Derived : Base&lt;T&gt; { <span class="dt">void</span> reset() { <span class="kw">this</span>-&gt;BadNamedMember = <span class="dv">0</span>; } };</code></pre></div> <p>After if AggressiveDependentMemberLookup is false:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">template</span> &lt;<span class="kw">typename</span> T&gt; <span class="kw">struct</span> Base { T bad_named_member; }; <span class="kw">template</span> &lt;<span class="kw">typename</span> T&gt; <span class="kw">struct</span> Derived : Base&lt;T&gt; { <span class="dt">void</span> reset() { <span class="kw">this</span>-&gt;BadNamedMember = <span class="dv">0</span>; } };</code></pre></div> <p>After if AggressiveDependentMemberLookup is true:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">template</span> &lt;<span class="kw">typename</span> T&gt; <span class="kw">struct</span> Base { T bad_named_member; }; <span class="kw">template</span> &lt;<span class="kw">typename</span> T&gt; <span class="kw">struct</span> Derived : Base&lt;T&gt; { <span class="dt">void</span> reset() { <span class="kw">this</span>-&gt;bad_named_member = <span class="dv">0</span>; } };</code></pre></div> <p>ClassCase</p> <p>When defined, the check will ensure class names conform to the selected casing.</p> <p>ClassPrefix</p> <p>When defined, the check will ensure class names will add the prefixed with the given value (regardless of casing).</p> <p>ClassIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for class names matching this regular expression.</p> <p>ClassSuffix</p> <p>When defined, the check will ensure class names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>ClassCase of lower_case</li> <li>ClassPrefix of pre_</li> <li>ClassSuffix of _post</li> </ul> <p>Identifies and/or transforms class names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> FOO { <span class="kw">public</span>: FOO(); ~FOO(); };</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> pre_foo_post { <span class="kw">public</span>: pre_foo_post(); ~pre_foo_post(); };</code></pre></div> <p>ClassConstantCase</p> <p>When defined, the check will ensure class constant names conform to the selected casing.</p> <p>ClassConstantPrefix</p> <p>When defined, the check will ensure class constant names will add the prefixed with the given value (regardless of casing).</p> <p>ClassConstantIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for class constant names matching this regular expression.</p> <p>ClassConstantSuffix</p> <p>When defined, the check will ensure class constant names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>ClassConstantCase of lower_case</li> <li>ClassConstantPrefix of pre_</li> <li>ClassConstantSuffix of _post</li> </ul> <p>Identifies and/or transforms class constant names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> FOO { <span class="kw">public</span>: <span class="dt">static</span> <span class="dt">const</span> <span class="dt">int</span> CLASS_CONSTANT; };</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> FOO { <span class="kw">public</span>: <span class="dt">static</span> <span class="dt">const</span> <span class="dt">int</span> pre_class_constant_post; };</code></pre></div> <p>ClassMemberCase</p> <p>When defined, the check will ensure class member names conform to the selected casing.</p> <p>ClassMemberPrefix</p> <p>When defined, the check will ensure class member names will add the prefixed with the given value (regardless of casing).</p> <p>ClassMemberIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for class member names matching this regular expression.</p> <p>ClassMemberSuffix</p> <p>When defined, the check will ensure class member names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>ClassMemberCase of lower_case</li> <li>ClassMemberPrefix of pre_</li> <li>ClassMemberSuffix of _post</li> </ul> <p>Identifies and/or transforms class member names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> FOO { <span class="kw">public</span>: <span class="dt">static</span> <span class="dt">int</span> CLASS_CONSTANT; };</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> FOO { <span class="kw">public</span>: <span class="dt">static</span> <span class="dt">int</span> pre_class_constant_post; };</code></pre></div> <p>ClassMethodCase</p> <p>When defined, the check will ensure class method names conform to the selected casing.</p> <p>ClassMethodPrefix</p> <p>When defined, the check will ensure class method names will add the prefixed with the given value (regardless of casing).</p> <p>ClassMethodIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for class method names matching this regular expression.</p> <p>ClassMethodSuffix</p> <p>When defined, the check will ensure class method names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>ClassMethodCase of lower_case</li> <li>ClassMethodPrefix of pre_</li> <li>ClassMethodSuffix of _post</li> </ul> <p>Identifies and/or transforms class method names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> FOO { <span class="kw">public</span>: <span class="dt">int</span> CLASS_MEMBER(); };</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> FOO { <span class="kw">public</span>: <span class="dt">int</span> pre_class_member_post(); };</code></pre></div> <p>ConstantCase</p> <p>When defined, the check will ensure constant names conform to the selected casing.</p> <p>ConstantPrefix</p> <p>When defined, the check will ensure constant names will add the prefixed with the given value (regardless of casing).</p> <p>ConstantIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for constant names matching this regular expression.</p> <p>ConstantSuffix</p> <p>When defined, the check will ensure constant names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>ConstantCase of lower_case</li> <li>ConstantPrefix of pre_</li> <li>ConstantSuffix of _post</li> </ul> <p>Identifies and/or transforms constant names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> function() { <span class="dt">unsigned</span> <span class="dt">const</span> MyConst_array[] = {<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>}; }</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> function() { <span class="dt">unsigned</span> <span class="dt">const</span> pre_myconst_array_post[] = {<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>}; }</code></pre></div> <p>ConstantMemberCase</p> <p>When defined, the check will ensure constant member names conform to the selected casing.</p> <p>ConstantMemberPrefix</p> <p>When defined, the check will ensure constant member names will add the prefixed with the given value (regardless of casing).</p> <p>ConstantMemberIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for constant member names matching this regular expression.</p> <p>ConstantMemberSuffix</p> <p>When defined, the check will ensure constant member names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>ConstantMemberCase of lower_case</li> <li>ConstantMemberPrefix of pre_</li> <li>ConstantMemberSuffix of _post</li> </ul> <p>Identifies and/or transforms constant member names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="dt">char</span> <span class="dt">const</span> MY_ConstMember_string[<span class="dv">4</span>] = <span class="st">&quot;123&quot;</span>; }</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="dt">char</span> <span class="dt">const</span> pre_my_constmember_string_post[<span class="dv">4</span>] = <span class="st">&quot;123&quot;</span>; }</code></pre></div> <p>ConstantParameterCase</p> <p>When defined, the check will ensure constant parameter names conform to the selected casing.</p> <p>ConstantParameterPrefix</p> <p>When defined, the check will ensure constant parameter names will add the prefixed with the given value (regardless of casing).</p> <p>ConstantParameterIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for constant parameter names matching this regular expression.</p> <p>ConstantParameterSuffix</p> <p>When defined, the check will ensure constant parameter names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>ConstantParameterCase of lower_case</li> <li>ConstantParameterPrefix of pre_</li> <li>ConstantParameterSuffix of _post</li> </ul> <p>Identifies and/or transforms constant parameter names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> GLOBAL_FUNCTION(<span class="dt">int</span> PARAMETER_1, <span class="dt">int</span> <span class="dt">const</span> CONST_parameter);</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> GLOBAL_FUNCTION(<span class="dt">int</span> PARAMETER_1, <span class="dt">int</span> <span class="dt">const</span> pre_const_parameter_post);</code></pre></div> <p>ConstantPointerParameterCase</p> <p>When defined, the check will ensure constant pointer parameter names conform to the selected casing.</p> <p>ConstantPointerParameterPrefix</p> <p>When defined, the check will ensure constant pointer parameter names will add the prefixed with the given value (regardless of casing).</p> <p>ConstantPointerParameterIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for constant pointer parameter names matching this regular expression.</p> <p>ConstantPointerParameterSuffix</p> <p>When defined, the check will ensure constant pointer parameter names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>ConstantPointerParameterCase of lower_case</li> <li>ConstantPointerParameterPrefix of pre_</li> <li>ConstantPointerParameterSuffix of _post</li> </ul> <p>Identifies and/or transforms constant pointer parameter names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> GLOBAL_FUNCTION(<span class="dt">int</span> <span class="dt">const</span> *CONST_parameter);</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> GLOBAL_FUNCTION(<span class="dt">int</span> <span class="dt">const</span> *pre_const_parameter_post);</code></pre></div> <p>ConstexprFunctionCase</p> <p>When defined, the check will ensure constexpr function names conform to the selected casing.</p> <p>ConstexprFunctionPrefix</p> <p>When defined, the check will ensure constexpr function names will add the prefixed with the given value (regardless of casing).</p> <p>ConstexprFunctionIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for constexpr function names matching this regular expression.</p> <p>ConstexprFunctionSuffix</p> <p>When defined, the check will ensure constexpr function names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>ConstexprFunctionCase of lower_case</li> <li>ConstexprFunctionPrefix of pre_</li> <li>ConstexprFunctionSuffix of _post</li> </ul> <p>Identifies and/or transforms constexpr function names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">constexpr</span> <span class="dt">int</span> CE_function() { <span class="kw">return</span> <span class="dv">3</span>; }</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">constexpr</span> <span class="dt">int</span> pre_ce_function_post() { <span class="kw">return</span> <span class="dv">3</span>; }</code></pre></div> <p>ConstexprMethodCase</p> <p>When defined, the check will ensure constexpr method names conform to the selected casing.</p> <p>ConstexprMethodPrefix</p> <p>When defined, the check will ensure constexpr method names will add the prefixed with the given value (regardless of casing).</p> <p>ConstexprMethodIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for constexpr method names matching this regular expression.</p> <p>ConstexprMethodSuffix</p> <p>When defined, the check will ensure constexpr method names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>ConstexprMethodCase of lower_case</li> <li>ConstexprMethodPrefix of pre_</li> <li>ConstexprMethodSuffix of _post</li> </ul> <p>Identifies and/or transforms constexpr method names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="kw">public</span>: <span class="kw">constexpr</span> <span class="dt">int</span> CST_expr_Method() { <span class="kw">return</span> <span class="dv">2</span>; } }</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="kw">public</span>: <span class="kw">constexpr</span> <span class="dt">int</span> pre_cst_expr_method_post() { <span class="kw">return</span> <span class="dv">2</span>; } }</code></pre></div> <p>ConstexprVariableCase</p> <p>When defined, the check will ensure constexpr variable names conform to the selected casing.</p> <p>ConstexprVariablePrefix</p> <p>When defined, the check will ensure constexpr variable names will add the prefixed with the given value (regardless of casing).</p> <p>ConstexprVariableIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for constexpr variable names matching this regular expression.</p> <p>ConstexprVariableSuffix</p> <p>When defined, the check will ensure constexpr variable names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>ConstexprVariableCase of lower_case</li> <li>ConstexprVariablePrefix of pre_</li> <li>ConstexprVariableSuffix of _post</li> </ul> <p>Identifies and/or transforms constexpr variable names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">constexpr</span> <span class="dt">int</span> ConstExpr_variable = MyConstant;</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">constexpr</span> <span class="dt">int</span> pre_constexpr_variable_post = MyConstant;</code></pre></div> <p>EnumCase</p> <p>When defined, the check will ensure enumeration names conform to the selected casing.</p> <p>EnumPrefix</p> <p>When defined, the check will ensure enumeration names will add the prefixed with the given value (regardless of casing).</p> <p>EnumIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for enumeration names matching this regular expression.</p> <p>EnumSuffix</p> <p>When defined, the check will ensure enumeration names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>EnumCase of lower_case</li> <li>EnumPrefix of pre_</li> <li>EnumSuffix of _post</li> </ul> <p>Identifies and/or transforms enumeration names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">enum</span> FOO { One, Two, Three };</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">enum</span> pre_foo_post { One, Two, Three };</code></pre></div> <p>EnumConstantCase</p> <p>When defined, the check will ensure enumeration constant names conform to the selected casing.</p> <p>EnumConstantPrefix</p> <p>When defined, the check will ensure enumeration constant names will add the prefixed with the given value (regardless of casing).</p> <p>EnumConstantIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for enumeration constant names matching this regular expression.</p> <p>EnumConstantSuffix</p> <p>When defined, the check will ensure enumeration constant names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>EnumConstantCase of lower_case</li> <li>EnumConstantPrefix of pre_</li> <li>EnumConstantSuffix of _post</li> </ul> <p>Identifies and/or transforms enumeration constant names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">enum</span> FOO { One, Two, Three };</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">enum</span> FOO { pre_One_post, pre_Two_post, pre_Three_post };</code></pre></div> <p>FunctionCase</p> <p>When defined, the check will ensure function names conform to the selected casing.</p> <p>FunctionPrefix</p> <p>When defined, the check will ensure function names will add the prefixed with the given value (regardless of casing).</p> <p>FunctionIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for function names matching this regular expression.</p> <p>FunctionSuffix</p> <p>When defined, the check will ensure function names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>FunctionCase of lower_case</li> <li>FunctionPrefix of pre_</li> <li>FunctionSuffix of _post</li> </ul> <p>Identifies and/or transforms function names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">char</span> MY_Function_string();</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">char</span> pre_my_function_string_post();</code></pre></div> <p>GetConfigPerFile</p> <p>When true the check will look for the configuration for where an identifier is declared. Useful for when included header files use a different style. Default value is true.</p> <p>GlobalConstantCase</p> <p>When defined, the check will ensure global constant names conform to the selected casing.</p> <p>GlobalConstantPrefix</p> <p>When defined, the check will ensure global constant names will add the prefixed with the given value (regardless of casing).</p> <p>GlobalConstantIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for global constant names matching this regular expression.</p> <p>GlobalConstantSuffix</p> <p>When defined, the check will ensure global constant names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>GlobalConstantCase of lower_case</li> <li>GlobalConstantPrefix of pre_</li> <li>GlobalConstantSuffix of _post</li> </ul> <p>Identifies and/or transforms global constant names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">const</span> MyConstGlobal_array[] = {<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>};</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">const</span> pre_myconstglobal_array_post[] = {<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>};</code></pre></div> <p>GlobalConstantPointerCase</p> <p>When defined, the check will ensure global constant pointer names conform to the selected casing.</p> <p>GlobalConstantPointerPrefix</p> <p>When defined, the check will ensure global constant pointer names will add the prefixed with the given value (regardless of casing).</p> <p>GlobalConstantPointerIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for global constant pointer names matching this regular expression.</p> <p>GlobalConstantPointerSuffix</p> <p>When defined, the check will ensure global constant pointer names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>GlobalConstantPointerCase of lower_case</li> <li>GlobalConstantPointerPrefix of pre_</li> <li>GlobalConstantPointerSuffix of _post</li> </ul> <p>Identifies and/or transforms global constant pointer names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> *<span class="dt">const</span> MyConstantGlobalPointer = <span class="kw">nullptr</span>;</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> *<span class="dt">const</span> pre_myconstantglobalpointer_post = <span class="kw">nullptr</span>;</code></pre></div> <p>GlobalFunctionCase</p> <p>When defined, the check will ensure global function names conform to the selected casing.</p> <p>GlobalFunctionPrefix</p> <p>When defined, the check will ensure global function names will add the prefixed with the given value (regardless of casing).</p> <p>GlobalFunctionIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for global function names matching this regular expression.</p> <p>GlobalFunctionSuffix</p> <p>When defined, the check will ensure global function names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>GlobalFunctionCase of lower_case</li> <li>GlobalFunctionPrefix of pre_</li> <li>GlobalFunctionSuffix of _post</li> </ul> <p>Identifies and/or transforms global function names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> GLOBAL_FUNCTION(<span class="dt">int</span> PARAMETER_1, <span class="dt">int</span> <span class="dt">const</span> CONST_parameter);</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> pre_global_function_post(<span class="dt">int</span> PARAMETER_1, <span class="dt">int</span> <span class="dt">const</span> CONST_parameter);</code></pre></div> <p>GlobalPointerCase</p> <p>When defined, the check will ensure global pointer names conform to the selected casing.</p> <p>GlobalPointerPrefix</p> <p>When defined, the check will ensure global pointer names will add the prefixed with the given value (regardless of casing).</p> <p>GlobalPointerIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for global pointer names matching this regular expression.</p> <p>GlobalPointerSuffix</p> <p>When defined, the check will ensure global pointer names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>GlobalPointerCase of lower_case</li> <li>GlobalPointerPrefix of pre_</li> <li>GlobalPointerSuffix of _post</li> </ul> <p>Identifies and/or transforms global pointer names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> *GLOBAL3;</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> *pre_global3_post;</code></pre></div> <p>GlobalVariableCase</p> <p>When defined, the check will ensure global variable names conform to the selected casing.</p> <p>GlobalVariablePrefix</p> <p>When defined, the check will ensure global variable names will add the prefixed with the given value (regardless of casing).</p> <p>GlobalVariableIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for global variable names matching this regular expression.</p> <p>GlobalVariableSuffix</p> <p>When defined, the check will ensure global variable names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>GlobalVariableCase of lower_case</li> <li>GlobalVariablePrefix of pre_</li> <li>GlobalVariableSuffix of _post</li> </ul> <p>Identifies and/or transforms global variable names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> GLOBAL3;</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> pre_global3_post;</code></pre></div> <p>IgnoreMainLikeFunctions</p> <p>When set to true functions that have a similar signature to main or wmain won’t enforce checks on the names of their parameters. Default value is false.</p> <p>InlineNamespaceCase</p> <p>When defined, the check will ensure inline namespaces names conform to the selected casing.</p> <p>InlineNamespacePrefix</p> <p>When defined, the check will ensure inline namespaces names will add the prefixed with the given value (regardless of casing).</p> <p>InlineNamespaceIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for inline namespaces names matching this regular expression.</p> <p>InlineNamespaceSuffix</p> <p>When defined, the check will ensure inline namespaces names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>InlineNamespaceCase of lower_case</li> <li>InlineNamespacePrefix of pre_</li> <li>InlineNamespaceSuffix of _post</li> </ul> <p>Identifies and/or transforms inline namespaces names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">namespace</span> FOO_NS { <span class="kw">inline</span> <span class="kw">namespace</span> InlineNamespace { ... } } <span class="co">// namespace FOO_NS</span></code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">namespace</span> FOO_NS { <span class="kw">inline</span> <span class="kw">namespace</span> pre_inlinenamespace_post { ... } } <span class="co">// namespace FOO_NS</span></code></pre></div> <p>LocalConstantCase</p> <p>When defined, the check will ensure local constant names conform to the selected casing.</p> <p>LocalConstantPrefix</p> <p>When defined, the check will ensure local constant names will add the prefixed with the given value (regardless of casing).</p> <p>LocalConstantIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for local constant names matching this regular expression.</p> <p>LocalConstantSuffix</p> <p>When defined, the check will ensure local constant names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>LocalConstantCase of lower_case</li> <li>LocalConstantPrefix of pre_</li> <li>LocalConstantSuffix of _post</li> </ul> <p>Identifies and/or transforms local constant names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo() { <span class="dt">int</span> <span class="dt">const</span> local_Constant = <span class="dv">3</span>; }</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo() { <span class="dt">int</span> <span class="dt">const</span> pre_local_constant_post = <span class="dv">3</span>; }</code></pre></div> <p>LocalConstantPointerCase</p> <p>When defined, the check will ensure local constant pointer names conform to the selected casing.</p> <p>LocalConstantPointerPrefix</p> <p>When defined, the check will ensure local constant pointer names will add the prefixed with the given value (regardless of casing).</p> <p>LocalConstantPointerIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for local constant pointer names matching this regular expression.</p> <p>LocalConstantPointerSuffix</p> <p>When defined, the check will ensure local constant pointer names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>LocalConstantPointerCase of lower_case</li> <li>LocalConstantPointerPrefix of pre_</li> <li>LocalConstantPointerSuffix of _post</li> </ul> <p>Identifies and/or transforms local constant pointer names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo() { <span class="dt">int</span> <span class="dt">const</span> *local_Constant = <span class="dv">3</span>; }</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo() { <span class="dt">int</span> <span class="dt">const</span> *pre_local_constant_post = <span class="dv">3</span>; }</code></pre></div> <p>LocalPointerCase</p> <p>When defined, the check will ensure local pointer names conform to the selected casing.</p> <p>LocalPointerPrefix</p> <p>When defined, the check will ensure local pointer names will add the prefixed with the given value (regardless of casing).</p> <p>LocalPointerIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for local pointer names matching this regular expression.</p> <p>LocalPointerSuffix</p> <p>When defined, the check will ensure local pointer names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>LocalPointerCase of lower_case</li> <li>LocalPointerPrefix of pre_</li> <li>LocalPointerSuffix of _post</li> </ul> <p>Identifies and/or transforms local pointer names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo() { <span class="dt">int</span> *local_Constant; }</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo() { <span class="dt">int</span> *pre_local_constant_post; }</code></pre></div> <p>LocalVariableCase</p> <p>When defined, the check will ensure local variable names conform to the selected casing.</p> <p>LocalVariablePrefix</p> <p>When defined, the check will ensure local variable names will add the prefixed with the given value (regardless of casing).</p> <p>LocalVariableIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for local variable names matching this regular expression.</p> <p>For example using values of:</p> <ul> <li>LocalVariableCase of CamelCase</li> <li>LocalVariableIgnoredRegexp of </li> </ul> <p>Will exclude variables with a length less than or equal to 2 from the camel case check applied to other variables.</p> <p>LocalVariableSuffix</p> <p>When defined, the check will ensure local variable names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>LocalVariableCase of lower_case</li> <li>LocalVariablePrefix of pre_</li> <li>LocalVariableSuffix of _post</li> </ul> <p>Identifies and/or transforms local variable names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo() { <span class="dt">int</span> local_Constant; }</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> foo() { <span class="dt">int</span> pre_local_constant_post; }</code></pre></div> <p>MacroDefinitionCase</p> <p>When defined, the check will ensure macro definitions conform to the selected casing.</p> <p>MacroDefinitionPrefix</p> <p>When defined, the check will ensure macro definitions will add the prefixed with the given value (regardless of casing).</p> <p>MacroDefinitionIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for macro definitions matching this regular expression.</p> <p>MacroDefinitionSuffix</p> <p>When defined, the check will ensure macro definitions will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>MacroDefinitionCase of lower_case</li> <li>MacroDefinitionPrefix of pre_</li> <li>MacroDefinitionSuffix of _post</li> </ul> <p>Identifies and/or transforms macro definitions as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#define MY_MacroDefinition</span></code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#define pre_my_macro_definition_post</span></code></pre></div> <p>Note: This will not warn on builtin macros or macros defined on the command line using the -D flag.</p> <p>MemberCase</p> <p>When defined, the check will ensure member names conform to the selected casing.</p> <p>MemberPrefix</p> <p>When defined, the check will ensure member names will add the prefixed with the given value (regardless of casing).</p> <p>MemberIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for member names matching this regular expression.</p> <p>MemberSuffix</p> <p>When defined, the check will ensure member names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>MemberCase of lower_case</li> <li>MemberPrefix of pre_</li> <li>MemberSuffix of _post</li> </ul> <p>Identifies and/or transforms member names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="dt">char</span> MY_ConstMember_string[<span class="dv">4</span>]; }</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="dt">char</span> pre_my_constmember_string_post[<span class="dv">4</span>]; }</code></pre></div> <p>MethodCase</p> <p>When defined, the check will ensure method names conform to the selected casing.</p> <p>MethodPrefix</p> <p>When defined, the check will ensure method names will add the prefixed with the given value (regardless of casing).</p> <p>MethodIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for method names matching this regular expression.</p> <p>MethodSuffix</p> <p>When defined, the check will ensure method names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>MethodCase of lower_case</li> <li>MethodPrefix of pre_</li> <li>MethodSuffix of _post</li> </ul> <p>Identifies and/or transforms method names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="dt">char</span> MY_Method_string(); }</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="dt">char</span> pre_my_method_string_post(); }</code></pre></div> <p>NamespaceCase</p> <p>When defined, the check will ensure namespace names conform to the selected casing.</p> <p>NamespacePrefix</p> <p>When defined, the check will ensure namespace names will add the prefixed with the given value (regardless of casing).</p> <p>NamespaceIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for namespace names matching this regular expression.</p> <p>NamespaceSuffix</p> <p>When defined, the check will ensure namespace names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>NamespaceCase of lower_case</li> <li>NamespacePrefix of pre_</li> <li>NamespaceSuffix of _post</li> </ul> <p>Identifies and/or transforms namespace names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">namespace</span> FOO_NS { ... }</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">namespace</span> pre_foo_ns_post { ... }</code></pre></div> <p>ParameterCase</p> <p>When defined, the check will ensure parameter names conform to the selected casing.</p> <p>ParameterPrefix</p> <p>When defined, the check will ensure parameter names will add the prefixed with the given value (regardless of casing).</p> <p>ParameterIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for parameter names matching this regular expression.</p> <p>ParameterSuffix</p> <p>When defined, the check will ensure parameter names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>ParameterCase of lower_case</li> <li>ParameterPrefix of pre_</li> <li>ParameterSuffix of _post</li> </ul> <p>Identifies and/or transforms parameter names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> GLOBAL_FUNCTION(<span class="dt">int</span> PARAMETER_1, <span class="dt">int</span> <span class="dt">const</span> CONST_parameter);</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> GLOBAL_FUNCTION(<span class="dt">int</span> pre_parameter_post, <span class="dt">int</span> <span class="dt">const</span> CONST_parameter);</code></pre></div> <p>ParameterPackCase</p> <p>When defined, the check will ensure parameter pack names conform to the selected casing.</p> <p>ParameterPackPrefix</p> <p>When defined, the check will ensure parameter pack names will add the prefixed with the given value (regardless of casing).</p> <p>ParameterPackIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for parameter pack names matching this regular expression.</p> <p>ParameterPackSuffix</p> <p>When defined, the check will ensure parameter pack names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>ParameterPackCase of lower_case</li> <li>ParameterPackPrefix of pre_</li> <li>ParameterPackSuffix of _post</li> </ul> <p>Identifies and/or transforms parameter pack names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">template</span> &lt;<span class="kw">typename</span>... TYPE_parameters&gt; { <span class="dt">void</span> FUNCTION(<span class="dt">int</span>... TYPE_parameters); }</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">template</span> &lt;<span class="kw">typename</span>... TYPE_parameters&gt; { <span class="dt">void</span> FUNCTION(<span class="dt">int</span>... pre_type_parameters_post); }</code></pre></div> <p>PointerParameterCase</p> <p>When defined, the check will ensure pointer parameter names conform to the selected casing.</p> <p>PointerParameterPrefix</p> <p>When defined, the check will ensure pointer parameter names will add the prefixed with the given value (regardless of casing).</p> <p>PointerParameterIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for pointer parameter names matching this regular expression.</p> <p>PointerParameterSuffix</p> <p>When defined, the check will ensure pointer parameter names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>PointerParameterCase of lower_case</li> <li>PointerParameterPrefix of pre_</li> <li>PointerParameterSuffix of _post</li> </ul> <p>Identifies and/or transforms pointer parameter names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> FUNCTION(<span class="dt">int</span> *PARAMETER);</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> FUNCTION(<span class="dt">int</span> *pre_parameter_post);</code></pre></div> <p>PrivateMemberCase</p> <p>When defined, the check will ensure private member names conform to the selected casing.</p> <p>PrivateMemberPrefix</p> <p>When defined, the check will ensure private member names will add the prefixed with the given value (regardless of casing).</p> <p>PrivateMemberIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for private member names matching this regular expression.</p> <p>PrivateMemberSuffix</p> <p>When defined, the check will ensure private member names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>PrivateMemberCase of lower_case</li> <li>PrivateMemberPrefix of pre_</li> <li>PrivateMemberSuffix of _post</li> </ul> <p>Identifies and/or transforms private member names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="kw">private</span>: <span class="dt">int</span> Member_Variable; }</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="kw">private</span>: <span class="dt">int</span> pre_member_variable_post; }</code></pre></div> <p>PrivateMethodCase</p> <p>When defined, the check will ensure private method names conform to the selected casing.</p> <p>PrivateMethodPrefix</p> <p>When defined, the check will ensure private method names will add the prefixed with the given value (regardless of casing).</p> <p>PrivateMethodIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for private method names matching this regular expression.</p> <p>PrivateMethodSuffix</p> <p>When defined, the check will ensure private method names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>PrivateMethodCase of lower_case</li> <li>PrivateMethodPrefix of pre_</li> <li>PrivateMethodSuffix of _post</li> </ul> <p>Identifies and/or transforms private method names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="kw">private</span>: <span class="dt">int</span> Member_Method(); }</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="kw">private</span>: <span class="dt">int</span> pre_member_method_post(); }</code></pre></div> <p>ProtectedMemberCase</p> <p>When defined, the check will ensure protected member names conform to the selected casing.</p> <p>ProtectedMemberPrefix</p> <p>When defined, the check will ensure protected member names will add the prefixed with the given value (regardless of casing).</p> <p>ProtectedMemberIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for protected member names matching this regular expression.</p> <p>ProtectedMemberSuffix</p> <p>When defined, the check will ensure protected member names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>ProtectedMemberCase of lower_case</li> <li>ProtectedMemberPrefix of pre_</li> <li>ProtectedMemberSuffix of _post</li> </ul> <p>Identifies and/or transforms protected member names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="kw">protected</span>: <span class="dt">int</span> Member_Variable; }</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="kw">protected</span>: <span class="dt">int</span> pre_member_variable_post; }</code></pre></div> <p>ProtectedMethodCase</p> <p>When defined, the check will ensure protected method names conform to the selected casing.</p> <p>ProtectedMethodPrefix</p> <p>When defined, the check will ensure protected method names will add the prefixed with the given value (regardless of casing).</p> <p>ProtectedMethodIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for protected method names matching this regular expression.</p> <p>ProtectedMethodSuffix</p> <p>When defined, the check will ensure protected method names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>ProtectedMethodCase of lower_case</li> <li>ProtectedMethodPrefix of pre_</li> <li>ProtectedMethodSuffix of _post</li> </ul> <p>Identifies and/or transforms protect method names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="kw">protected</span>: <span class="dt">int</span> Member_Method(); }</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="kw">protected</span>: <span class="dt">int</span> pre_member_method_post(); }</code></pre></div> <p>PublicMemberCase</p> <p>When defined, the check will ensure public member names conform to the selected casing.</p> <p>PublicMemberPrefix</p> <p>When defined, the check will ensure public member names will add the prefixed with the given value (regardless of casing).</p> <p>PublicMemberIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for public member names matching this regular expression.</p> <p>PublicMemberSuffix</p> <p>When defined, the check will ensure public member names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>PublicMemberCase of lower_case</li> <li>PublicMemberPrefix of pre_</li> <li>PublicMemberSuffix of _post</li> </ul> <p>Identifies and/or transforms public member names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="kw">public</span>: <span class="dt">int</span> Member_Variable; }</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="kw">public</span>: <span class="dt">int</span> pre_member_variable_post; }</code></pre></div> <p>PublicMethodCase</p> <p>When defined, the check will ensure public method names conform to the selected casing.</p> <p>PublicMethodPrefix</p> <p>When defined, the check will ensure public method names will add the prefixed with the given value (regardless of casing).</p> <p>PublicMethodIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for public method names matching this regular expression.</p> <p>PublicMethodSuffix</p> <p>When defined, the check will ensure public method names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>PublicMethodCase of lower_case</li> <li>PublicMethodPrefix of pre_</li> <li>PublicMethodSuffix of _post</li> </ul> <p>Identifies and/or transforms public method names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="kw">public</span>: <span class="dt">int</span> Member_Method(); }</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="kw">public</span>: <span class="dt">int</span> pre_member_method_post(); }</code></pre></div> <p>ScopedEnumConstantCase</p> <p>When defined, the check will ensure scoped enum constant names conform to the selected casing.</p> <p>ScopedEnumConstantPrefix</p> <p>When defined, the check will ensure scoped enum constant names will add the prefixed with the given value (regardless of casing).</p> <p>ScopedEnumConstantIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for scoped enum constant names matching this regular expression.</p> <p>ScopedEnumConstantSuffix</p> <p>When defined, the check will ensure scoped enum constant names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>ScopedEnumConstantCase of lower_case</li> <li>ScopedEnumConstantPrefix of pre_</li> <li>ScopedEnumConstantSuffix of _post</li> </ul> <p>Identifies and/or transforms enumeration constant names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">enum</span> <span class="kw">class</span> FOO { One, Two, Three };</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">enum</span> <span class="kw">class</span> FOO { pre_One_post, pre_Two_post, pre_Three_post };</code></pre></div> <p>StaticConstantCase</p> <p>When defined, the check will ensure static constant names conform to the selected casing.</p> <p>StaticConstantPrefix</p> <p>When defined, the check will ensure static constant names will add the prefixed with the given value (regardless of casing).</p> <p>StaticConstantIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for static constant names matching this regular expression.</p> <p>StaticConstantSuffix</p> <p>When defined, the check will ensure static constant names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>StaticConstantCase of lower_case</li> <li>StaticConstantPrefix of pre_</li> <li>StaticConstantSuffix of _post</li> </ul> <p>Identifies and/or transforms static constant names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">static</span> <span class="dt">unsigned</span> <span class="dt">const</span> MyConstStatic_array[] = {<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>};</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">static</span> <span class="dt">unsigned</span> <span class="dt">const</span> pre_myconststatic_array_post[] = {<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>};</code></pre></div> <p>StaticVariableCase</p> <p>When defined, the check will ensure static variable names conform to the selected casing.</p> <p>StaticVariablePrefix</p> <p>When defined, the check will ensure static variable names will add the prefixed with the given value (regardless of casing).</p> <p>StaticVariableIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for static variable names matching this regular expression.</p> <p>StaticVariableSuffix</p> <p>When defined, the check will ensure static variable names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>StaticVariableCase of lower_case</li> <li>StaticVariablePrefix of pre_</li> <li>StaticVariableSuffix of _post</li> </ul> <p>Identifies and/or transforms static variable names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">static</span> <span class="dt">unsigned</span> MyStatic_array[] = {<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>};</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">static</span> <span class="dt">unsigned</span> pre_mystatic_array_post[] = {<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>};</code></pre></div> <p>StructCase</p> <p>When defined, the check will ensure struct names conform to the selected casing.</p> <p>StructPrefix</p> <p>When defined, the check will ensure struct names will add the prefixed with the given value (regardless of casing).</p> <p>StructIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for struct names matching this regular expression.</p> <p>StructSuffix</p> <p>When defined, the check will ensure struct names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>StructCase of lower_case</li> <li>StructPrefix of pre_</li> <li>StructSuffix of _post</li> </ul> <p>Identifies and/or transforms struct names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> FOO { FOO(); ~FOO(); };</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> pre_foo_post { pre_foo_post(); ~pre_foo_post(); };</code></pre></div> <p>TemplateParameterCase</p> <p>When defined, the check will ensure template parameter names conform to the selected casing.</p> <p>TemplateParameterPrefix</p> <p>When defined, the check will ensure template parameter names will add the prefixed with the given value (regardless of casing).</p> <p>TemplateParameterIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for template parameter names matching this regular expression.</p> <p>TemplateParameterSuffix</p> <p>When defined, the check will ensure template parameter names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>TemplateParameterCase of lower_case</li> <li>TemplateParameterPrefix of pre_</li> <li>TemplateParameterSuffix of _post</li> </ul> <p>Identifies and/or transforms template parameter names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">template</span> &lt;<span class="kw">typename</span> T&gt; <span class="kw">class</span> Foo {};</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">template</span> &lt;<span class="kw">typename</span> pre_t_post&gt; <span class="kw">class</span> Foo {};</code></pre></div> <p>TemplateTemplateParameterCase</p> <p>When defined, the check will ensure template template parameter names conform to the selected casing.</p> <p>TemplateTemplateParameterPrefix</p> <p>When defined, the check will ensure template template parameter names will add the prefixed with the given value (regardless of casing).</p> <p>TemplateTemplateParameterIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for template template parameter names matching this regular expression.</p> <p>TemplateTemplateParameterSuffix</p> <p>When defined, the check will ensure template template parameter names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>TemplateTemplateParameterCase of lower_case</li> <li>TemplateTemplateParameterPrefix of pre_</li> <li>TemplateTemplateParameterSuffix of _post</li> </ul> <p>Identifies and/or transforms template template parameter names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">template</span> &lt;<span class="kw">template</span> &lt;<span class="kw">typename</span>&gt; <span class="kw">class</span> TPL_parameter, <span class="dt">int</span> COUNT_params, <span class="kw">typename</span>... TYPE_parameters&gt;</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">template</span> &lt;<span class="kw">template</span> &lt;<span class="kw">typename</span>&gt; <span class="kw">class</span> pre_tpl_parameter_post, <span class="dt">int</span> COUNT_params, <span class="kw">typename</span>... TYPE_parameters&gt;</code></pre></div> <p>TypeAliasCase</p> <p>When defined, the check will ensure type alias names conform to the selected casing.</p> <p>TypeAliasPrefix</p> <p>When defined, the check will ensure type alias names will add the prefixed with the given value (regardless of casing).</p> <p>TypeAliasIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for type alias names matching this regular expression.</p> <p>TypeAliasSuffix</p> <p>When defined, the check will ensure type alias names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>TypeAliasCase of lower_case</li> <li>TypeAliasPrefix of pre_</li> <li>TypeAliasSuffix of _post</li> </ul> <p>Identifies and/or transforms type alias names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">using</span> MY_STRUCT_TYPE = my_structure;</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">using</span> pre_my_struct_type_post = my_structure;</code></pre></div> <p>TypedefCase</p> <p>When defined, the check will ensure typedef names conform to the selected casing.</p> <p>TypedefPrefix</p> <p>When defined, the check will ensure typedef names will add the prefixed with the given value (regardless of casing).</p> <p>TypedefIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for typedef names matching this regular expression.</p> <p>TypedefSuffix</p> <p>When defined, the check will ensure typedef names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>TypedefCase of lower_case</li> <li>TypedefPrefix of pre_</li> <li>TypedefSuffix of _post</li> </ul> <p>Identifies and/or transforms typedef names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">typedef</span> <span class="dt">int</span> MYINT;</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">typedef</span> <span class="dt">int</span> pre_myint_post;</code></pre></div> <p>TypeTemplateParameterCase</p> <p>When defined, the check will ensure type template parameter names conform to the selected casing.</p> <p>TypeTemplateParameterPrefix</p> <p>When defined, the check will ensure type template parameter names will add the prefixed with the given value (regardless of casing).</p> <p>TypeTemplateParameterIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for type template names matching this regular expression.</p> <p>TypeTemplateParameterSuffix</p> <p>When defined, the check will ensure type template parameter names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>TypeTemplateParameterCase of lower_case</li> <li>TypeTemplateParameterPrefix of pre_</li> <li>TypeTemplateParameterSuffix of _post</li> </ul> <p>Identifies and/or transforms type template parameter names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">template</span> &lt;<span class="kw">template</span> &lt;<span class="kw">typename</span>&gt; <span class="kw">class</span> TPL_parameter, <span class="dt">int</span> COUNT_params, <span class="kw">typename</span>... TYPE_parameters&gt;</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">template</span> &lt;<span class="kw">template</span> &lt;<span class="kw">typename</span>&gt; <span class="kw">class</span> TPL_parameter, <span class="dt">int</span> COUNT_params, <span class="kw">typename</span>... pre_type_parameters_post&gt;</code></pre></div> <p>UnionCase</p> <p>When defined, the check will ensure union names conform to the selected casing.</p> <p>UnionPrefix</p> <p>When defined, the check will ensure union names will add the prefixed with the given value (regardless of casing).</p> <p>UnionIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for union names matching this regular expression.</p> <p>UnionSuffix</p> <p>When defined, the check will ensure union names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>UnionCase of lower_case</li> <li>UnionPrefix of pre_</li> <li>UnionSuffix of _post</li> </ul> <p>Identifies and/or transforms union names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">union</span> FOO { <span class="dt">int</span> a; <span class="dt">char</span> b; };</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">union</span> pre_foo_post { <span class="dt">int</span> a; <span class="dt">char</span> b; };</code></pre></div> <p>ValueTemplateParameterCase</p> <p>When defined, the check will ensure value template parameter names conform to the selected casing.</p> <p>ValueTemplateParameterPrefix</p> <p>When defined, the check will ensure value template parameter names will add the prefixed with the given value (regardless of casing).</p> <p>ValueTemplateParameterIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for value template parameter names matching this regular expression.</p> <p>ValueTemplateParameterSuffix</p> <p>When defined, the check will ensure value template parameter names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>ValueTemplateParameterCase of lower_case</li> <li>ValueTemplateParameterPrefix of pre_</li> <li>ValueTemplateParameterSuffix of _post</li> </ul> <p>Identifies and/or transforms value template parameter names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">template</span> &lt;<span class="kw">template</span> &lt;<span class="kw">typename</span>&gt; <span class="kw">class</span> TPL_parameter, <span class="dt">int</span> COUNT_params, <span class="kw">typename</span>... TYPE_parameters&gt;</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">template</span> &lt;<span class="kw">template</span> &lt;<span class="kw">typename</span>&gt; <span class="kw">class</span> TPL_parameter, <span class="dt">int</span> pre_count_params_post, <span class="kw">typename</span>... TYPE_parameters&gt;</code></pre></div> <p>VariableCase</p> <p>When defined, the check will ensure variable names conform to the selected casing.</p> <p>VariablePrefix</p> <p>When defined, the check will ensure variable names will add the prefixed with the given value (regardless of casing).</p> <p>VariableIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for variable names matching this regular expression.</p> <p>VariableSuffix</p> <p>When defined, the check will ensure variable names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>VariableCase of lower_case</li> <li>VariablePrefix of pre_</li> <li>VariableSuffix of _post</li> </ul> <p>Identifies and/or transforms variable names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">unsigned</span> MyVariable;</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">unsigned</span> pre_myvariable_post;</code></pre></div> <p>VirtualMethodCase</p> <p>When defined, the check will ensure virtual method names conform to the selected casing.</p> <p>VirtualMethodPrefix</p> <p>When defined, the check will ensure virtual method names will add the prefixed with the given value (regardless of casing).</p> <p>VirtualMethodIgnoredRegexp</p> <p>Identifier naming checks won’t be enforced for virtual method names matching this regular expression.</p> <p>VirtualMethodSuffix</p> <p>When defined, the check will ensure virtual method names will add the suffix with the given value (regardless of casing).</p> <p>For example using values of:</p> <ul> <li>VirtualMethodCase of lower_case</li> <li>VirtualMethodPrefix of pre_</li> <li>VirtualMethodSuffix of _post</li> </ul> <p>Identifies and/or transforms virtual method names as follows:</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="kw">public</span>: <span class="kw">virtual</span> <span class="dt">int</span> MemberFunction(); }</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="kw">public</span>: <span class="kw">virtual</span> <span class="dt">int</span> pre_member_function_post(); }</code></pre></div> <p>(Clang-Tidy original name: readability-identifier-naming)</p> + + + + Major + + + + + + + true + false + readability-misplaced-array-index + readability + + true + Misplaced Array Index + <p>This check warns for unusual array index syntax.</p> <p>The following code has unusual array index syntax:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> f(<span class="dt">int</span> *X, <span class="dt">int</span> Y) { Y[X] = <span class="dv">0</span>; }</code></pre></div> <p>becomes</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> f(<span class="dt">int</span> *X, <span class="dt">int</span> Y) { X[Y] = <span class="dv">0</span>; }</code></pre></div> <p>The check warns about such unusual syntax for readability reasons:</p> <ul> <li>There are programmers that are not familiar with this unusual syntax.</li> <li>It is possible that variables are mixed up.</li> </ul> <p>(Clang-Tidy original name: readability-misplaced-array-index)</p> + + + + Major + + + + + + + true + false + readability-misleading-indentation + readability + + true + Misleading Indentation + <p>Correct indentation helps to understand code. Mismatch of the syntactical structure and the indentation of the code may hide serious problems. Missing braces can also make it significantly harder to read the code, therefore it is important to use braces.</p> <p>The way to avoid dangling else is to always check that an else belongs to the if that begins in the same column.</p> <p>You can omit braces when your inner part of e.g. an if statement has only one statement in it. Although in that case you should begin the next statement in the same column with the if.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Dangling else:</span> <span class="kw">if</span> (cond1) <span class="kw">if</span> (cond2) foo1(); <span class="kw">else</span> foo2(); <span class="co">// Wrong indentation: else belongs to if(cond2) statement.</span> <span class="co">// Missing braces:</span> <span class="kw">if</span> (cond1) foo1(); foo2(); <span class="co">// Not guarded by if(cond1).</span></code></pre></div> <h5 id="limitations-1">Limitations</h5> <p>Note that this check only works as expected when the tabs or spaces are used consistently and not mixed.</p> <p>(Clang-Tidy original name: readability-misleading-indentation)</p> + + + + Major + + + + + + + true + false + readability-make-member-function-const + readability + + true + Make Member Function Const + <p>Finds non-static member functions that can be made const because the functions don’t use this in a non-const way.</p> <p>This check tries to annotate methods according to <a href="https://isocpp.org/wiki/faq/const-correctness#logical-vs-physical-state">logical constness</a> (not physical constness). Therefore, it will suggest to add a const qualifier to a non-const method only if this method does something that is already possible though the public interface on a const pointer to the object:</p> <ul> <li>reading a public member variable</li> <li>calling a public const-qualified member function</li> <li>returning const-qualified this</li> <li>passing const-qualified this as a parameter.</li> </ul> <p>This check will also suggest to add a const qualifier to a non-const method if this method uses private data and functions in a limited number of ways where logical constness and physical constness coincide:</p> <ul> <li>reading a member variable of builtin type</li> </ul> <p>Specifically, this check will not suggest to add a const to a non-const method if the method reads a private member variable of pointer type because that allows to modify the pointee which might not preserve logical constness. For the same reason, it does not allow to call private member functions or member functions on private member variables.</p> <p>In addition, this check ignores functions that</p> <ul> <li>are declared virtual</li> <li>contain a const_cast</li> <li>are templated or part of a class template</li> <li>have an empty body</li> <li>do not (implicitly) use this at all (see <a href="readability-convert-member-functions-to-static.html">readability-convert-member-functions-to-static</a>).</li> </ul> <p>The following real-world examples will be preserved by the check:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> E1 { Pimpl &amp;getPimpl() <span class="dt">const</span>; <span class="kw">public</span>: <span class="dt">int</span> &amp;get() { <span class="co">// Calling a private member function disables this check.</span> <span class="kw">return</span> getPimpl()-&gt;i; } ... }; <span class="kw">class</span> E2 { <span class="kw">public</span>: <span class="dt">const</span> <span class="dt">int</span> *get() <span class="dt">const</span>; <span class="co">// const_cast disables this check.</span> S *get() { <span class="kw">return</span> <span class="kw">const_cast</span>&lt;<span class="dt">int</span>*&gt;(<span class="kw">const_cast</span>&lt;<span class="dt">const</span> C*&gt;(<span class="kw">this</span>)-&gt;get()); } ... };</code></pre></div> <p>After applying modifications as suggested by the check, running the check again might find more opportunities to mark member functions const.</p> <p>(Clang-Tidy original name: readability-make-member-function-const)</p> + + + + Major + + + + + + + true + false + readability-magic-numbers + readability + + true + Magic Numbers + <p>Detects magic numbers, integer or floating point literals that are embedded in code and not introduced via constants or symbols.</p> <p>Many coding guidelines advise replacing the magic values with symbolic constants to improve readability. Here are a few references:</p> <ul> <li><a href="https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-magic">Rule ES.45: Avoid “magic constants”; use symbolic constants in C++ Core Guidelines</a></li> <li><a href="http://www.codingstandard.com/rule/5-1-1-use-symbolic-names-instead-of-literal-values-in-code/">Rule 5.1.1 Use symbolic names instead of literal values in code in High Integrity C++</a></li> <li>Item 17 in “C++ Coding Standards: 101 Rules, Guidelines and Best Practices” by Herb Sutter and Andrei Alexandrescu</li> <li>Chapter 17 in “Clean Code - A handbook of agile software craftsmanship.” by Robert C. Martin</li> <li>Rule 20701 in “TRAIN REAL TIME DATA PROTOCOL Coding Rules” by Armin-Hagen Weiss, Bombardier</li> <li><a href="http://wiki.c2.com/?MagicNumber" class="uri">http://wiki.c2.com/?MagicNumber</a></li> </ul> <p>Examples of magic values:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">double</span> circleArea = <span class="fl">3.1415926535</span> * radius * radius; <span class="dt">double</span> totalCharge = <span class="fl">1.08</span> * itemPrice; <span class="dt">int</span> getAnswer() { <span class="kw">return</span> <span class="dv">-3</span>; <span class="co">// FILENOTFOUND</span> } <span class="kw">for</span> (<span class="dt">int</span> mm = <span class="dv">1</span>; mm &lt;= <span class="dv">12</span>; ++mm) { std::cout &lt;&lt; month[mm] &lt;&lt; <span class="st">&#39;</span><span class="ch">\n</span><span class="st">&#39;</span>; }</code></pre></div> <p>Example with magic values refactored:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">double</span> circleArea = M_PI * radius * radius; <span class="dt">const</span> <span class="dt">double</span> TAX_RATE = <span class="fl">0.08</span>; <span class="co">// or make it variable and read from a file</span> <span class="dt">double</span> totalCharge = (<span class="fl">1.0</span> + TAX_RATE) * itemPrice; <span class="dt">int</span> getAnswer() { <span class="kw">return</span> E_FILE_NOT_FOUND; } <span class="kw">for</span> (<span class="dt">int</span> mm = <span class="dv">1</span>; mm &lt;= MONTHS_IN_A_YEAR; ++mm) { std::cout &lt;&lt; month[mm] &lt;&lt; <span class="st">&#39;</span><span class="ch">\n</span><span class="st">&#39;</span>; }</code></pre></div> <p>For integral literals by default only 0 and 1 (and -1) integer values are accepted without a warning. This can be overridden with the <a href="#cmdoption-arg-ignoredintegervalues">IgnoredIntegerValues</a> option. Negative values are accepted if their absolute value is present in the <a href="#cmdoption-arg-ignoredintegervalues">IgnoredIntegerValues</a> list.</p> <p>As a special case for integral values, all powers of two can be accepted without warning by enabling the <a href="#cmdoption-arg-ignorepowersof2integervalues">IgnorePowersOf2IntegerValues</a> option.</p> <p>For floating point literals by default the 0.0 floating point value is accepted without a warning. The set of ignored floating point literals can be configured using the <a href="#cmdoption-arg-ignoredfloatingpointvalues">IgnoredFloatingPointValues</a> option. For each value in that set, the given string value is converted to a floating-point value representation used by the target architecture. If a floating-point literal value compares equal to one of the converted values, then that literal is not diagnosed by this check. Because floating-point equality is used to determine whether to diagnose or not, the user needs to be aware of the details of floating-point representations for any values that cannot be precisely represented for their target architecture.</p> <p>For each value in the <a href="#cmdoption-arg-ignoredfloatingpointvalues">IgnoredFloatingPointValues</a> set, both the single-precision form and double-precision form are accepted (for example, if 3.14 is in the set, neither 3.14f nor 3.14 will produce a warning).</p> <p>Scientific notation is supported for both source code input and option. Alternatively, the check for the floating point numbers can be disabled for all floating point values by enabling the <a href="#cmdoption-arg-ignoreallfloatingpointvalues">IgnoreAllFloatingPointValues</a> option.</p> <p>Since values 0 and 0.0 are so common as the base counter of loops, or initialization values for sums, they are always accepted without warning, even if not present in the respective ignored values list.</p> <h5 id="options-41">Options</h5> <p>IgnoredIntegerValues</p> <p>Semicolon-separated list of magic positive integers that will be accepted without a warning. Default values are {1, 2, 3, 4}, and 0 is accepted unconditionally.</p> <p>IgnorePowersOf2IntegerValues</p> <p>Boolean value indicating whether to accept all powers-of-two integer values without warning. Default value is false.</p> <p>IgnoredFloatingPointValues</p> <p>Semicolon-separated list of magic positive floating point values that will be accepted without a warning. Default values are {1.0, 100.0} and 0.0 is accepted unconditionally.</p> <p>IgnoreAllFloatingPointValues</p> <p>Boolean value indicating whether to accept all floating point values without warning. Default value is false.</p> <p>IgnoreBitFieldsWidths</p> <p>Boolean value indicating whether to accept magic numbers as bit field widths without warning. This is useful for example for register definitions which are generated from hardware specifications. Default value is true.</p> <p>(Clang-Tidy original name: readability-magic-numbers)</p> + + + + Major + + + + + + + true + false + readability-non-const-parameter + readability + + true + Non Const Parameter + <p>The check finds function parameters of a pointer type that could be changed to point to a constant type instead.</p> <p>When const is used properly, many mistakes can be avoided. Advantages when using const properly:</p> <ul> <li>prevent unintentional modification of data;</li> <li>get additional warnings such as using uninitialized data;</li> <li>make it easier for developers to see possible side effects.</li> </ul> <p>This check is not strict about constness, it only warns when the constness will make the function interface safer.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// warning here; the declaration &quot;const char *p&quot; would make the function</span> <span class="co">// interface safer.</span> <span class="dt">char</span> f1(<span class="dt">char</span> *p) { <span class="kw">return</span> *p; } <span class="co">// no warning; the declaration could be more const &quot;const int * const p&quot; but</span> <span class="co">// that does not make the function interface safer.</span> <span class="dt">int</span> f2(<span class="dt">const</span> <span class="dt">int</span> *p) { <span class="kw">return</span> *p; } <span class="co">// no warning; making x const does not make the function interface safer</span> <span class="dt">int</span> f3(<span class="dt">int</span> x) { <span class="kw">return</span> x; } <span class="co">// no warning; Technically, *p can be const (&quot;const struct S *p&quot;). But making</span> <span class="co">// *p const could be misleading. People might think that it&#39;s safe to pass</span> <span class="co">// const data to this function.</span> <span class="kw">struct</span> S { <span class="dt">int</span> *a; <span class="dt">int</span> *b; }; <span class="dt">int</span> f3(<span class="kw">struct</span> S *p) { *(p-&gt;a) = <span class="dv">0</span>; }</code></pre></div> <p>(Clang-Tidy original name: readability-non-const-parameter)</p> + + + + Major + + + + + + + true + false + readability-named-parameter + readability + + true + Named Parameter + <p>Find functions with unnamed arguments.</p> <p>The check implements the following rule originating in the Google C++ Style Guide:</p> <p><a href="https://google.github.io/styleguide/cppguide.html\#Function_Declarations_and_Definitions" class="uri">https://google.github.io/styleguide/cppguide.html\#Function_Declarations_and_Definitions</a></p> <p>All parameters should be named, with identical names in the declaration and implementation.</p> <p>Corresponding cpplint.py check name: readability/function.</p> <p>(Clang-Tidy original name: readability-named-parameter)</p> + + + + Major + + + + + + + true + false + readability-qualified-auto + readability + + true + Qualified Auto + <p>Adds pointer qualifications to auto-typed variables that are deduced to pointers.</p> <p><a href="https://llvm.org/docs/CodingStandards.html#beware-unnecessary-copies-with-auto">LLVM Coding Standards</a> advises to make it obvious if a auto typed variable is a pointer. This check will transform auto to auto * when the type is deduced to be a pointer.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">for</span> (<span class="kw">auto</span> Data : MutatablePtrContainer) { change(*Data); } <span class="kw">for</span> (<span class="kw">auto</span> Data : ConstantPtrContainer) { observe(*Data); }</code></pre></div> <p>Would be transformed into:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">for</span> (<span class="kw">auto</span> *Data : MutatablePtrContainer) { change(*Data); } <span class="kw">for</span> (<span class="dt">const</span> <span class="kw">auto</span> *Data : ConstantPtrContainer) { observe(*Data); }</code></pre></div> <p>Note const volatile qualified types will retain their const and volatile qualifiers. Pointers to pointers will not be fully qualified.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">const</span> <span class="kw">auto</span> Foo = cast&lt;<span class="dt">int</span> *&gt;(Baz1); <span class="dt">const</span> <span class="kw">auto</span> Bar = cast&lt;<span class="dt">const</span> <span class="dt">int</span> *&gt;(Baz2); <span class="dt">volatile</span> <span class="kw">auto</span> FooBar = cast&lt;<span class="dt">int</span> *&gt;(Baz3); <span class="kw">auto</span> BarFoo = cast&lt;<span class="dt">int</span> **&gt;(Baz4);</code></pre></div> <p>Would be transformed into:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">auto</span> *<span class="dt">const</span> Foo = cast&lt;<span class="dt">int</span> *&gt;(Baz1); <span class="dt">const</span> <span class="kw">auto</span> *<span class="dt">const</span> Bar = cast&lt;<span class="dt">const</span> <span class="dt">int</span> *&gt;(Baz2); <span class="kw">auto</span> *<span class="dt">volatile</span> FooBar = cast&lt;<span class="dt">int</span> *&gt;(Baz3); <span class="kw">auto</span> *BarFoo = cast&lt;<span class="dt">int</span> **&gt;(Baz4);</code></pre></div> <h5 id="options-15">Options</h5> <p>AddConstToQualified</p> <p>When set to true the check will add const qualifiers variables defined as auto * or auto &amp; when applicable. Default value is true.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">auto</span> Foo1 = cast&lt;<span class="dt">const</span> <span class="dt">int</span> *&gt;(Bar1); <span class="kw">auto</span> *Foo2 = cast&lt;<span class="dt">const</span> <span class="dt">int</span> *&gt;(Bar2); <span class="kw">auto</span> &amp;Foo3 = cast&lt;<span class="dt">const</span> <span class="dt">int</span> &amp;&gt;(Bar3);</code></pre></div> <p>If AddConstToQualified is set to false, it will be transformed into:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">const</span> <span class="kw">auto</span> *Foo1 = cast&lt;<span class="dt">const</span> <span class="dt">int</span> *&gt;(Bar1); <span class="kw">auto</span> *Foo2 = cast&lt;<span class="dt">const</span> <span class="dt">int</span> *&gt;(Bar2); <span class="kw">auto</span> &amp;Foo3 = cast&lt;<span class="dt">const</span> <span class="dt">int</span> &amp;&gt;(Bar3);</code></pre></div> <p>Otherwise it will be transformed into:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">const</span> <span class="kw">auto</span> *Foo1 = cast&lt;<span class="dt">const</span> <span class="dt">int</span> *&gt;(Bar1); <span class="dt">const</span> <span class="kw">auto</span> *Foo2 = cast&lt;<span class="dt">const</span> <span class="dt">int</span> *&gt;(Bar2); <span class="dt">const</span> <span class="kw">auto</span> &amp;Foo3 = cast&lt;<span class="dt">const</span> <span class="dt">int</span> &amp;&gt;(Bar3);</code></pre></div> <p>Note in the LLVM alias, the default value is false.</p> <p>(Clang-Tidy original name: readability-qualified-auto)</p> + + + + Major + + + + + + + true + false + readability-redundant-access-specifiers + readability + + true + Redundant Access Specifiers + <p>Finds classes, structs, and unions containing redundant member (field and method) access specifiers.</p> <h5 id="example-9">Example</h5> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Foo { <span class="kw">public</span>: <span class="dt">int</span> x; <span class="dt">int</span> y; <span class="kw">public</span>: <span class="dt">int</span> z; <span class="kw">protected</span>: <span class="dt">int</span> a; <span class="kw">public</span>: <span class="dt">int</span> c; }</code></pre></div> <p>In the example above, the second public declaration can be removed without any changes of behavior.</p> <h5 id="options-67">Options</h5> <p>CheckFirstDeclaration</p> <p>If set to true, the check will also diagnose if the first access specifier declaration is redundant (e.g. private inside class, or public inside struct or union). Default is false.</p> <h6 id="example-10">Example</h6> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> Bar { <span class="kw">public</span>: <span class="dt">int</span> x; }</code></pre></div> <p>If CheckFirstDeclaration option is enabled, a warning about redundant access specifier will be emitted, because public is the default member access for structs.</p> <p>(Clang-Tidy original name: readability-redundant-access-specifiers)</p> + + + + Major + + + + + + + true + false + readability-redundant-control-flow + readability + + true + Redundant Control Flow + <p>This check looks for procedures (functions returning no value) with return statements at the end of the function. Such return statements are redundant.</p> <p>Loop statements (for, while, do while) are checked for redundant continue statements at the end of the loop body.</p> <p>Examples:</p> <p>The following function f contains a redundant return statement:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">extern</span> <span class="dt">void</span> g(); <span class="dt">void</span> f() { g(); <span class="kw">return</span>; }</code></pre></div> <p>becomes</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">extern</span> <span class="dt">void</span> g(); <span class="dt">void</span> f() { g(); }</code></pre></div> <p>The following function k contains a redundant continue statement:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> k() { <span class="kw">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; <span class="dv">10</span>; ++i) { <span class="kw">continue</span>; } }</code></pre></div> <p>becomes</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> k() { <span class="kw">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; <span class="dv">10</span>; ++i) { } }</code></pre></div> <p>(Clang-Tidy original name: readability-redundant-control-flow)</p> + + + + Major + + + + + + + true + false + readability-redundant-declaration + readability + + true + Redundant Declaration + <p>Finds redundant variable and function declarations.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">extern</span> <span class="dt">int</span> X; <span class="dt">extern</span> <span class="dt">int</span> X;</code></pre></div> <p>becomes</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">extern</span> <span class="dt">int</span> X;</code></pre></div> <p>Such redundant declarations can be removed without changing program behaviour. They can for instance be unintentional left overs from previous refactorings when code has been moved around. Having redundant declarations could in worst case mean that there are typos in the code that cause bugs.</p> <p>Normally the code can be automatically fixed, <strong>clang-tidy</strong> can remove the second declaration. However there are 2 cases when you need to fix the code manually:</p> <ul> <li>When the declarations are in different header files;</li> <li>When multiple variables are declared together.</li> </ul> <h5 id="options-66">Options</h5> <p>IgnoreMacros</p> <p>If set to true, the check will not give warnings inside macros. Default is true.</p> <p>(Clang-Tidy original name: readability-redundant-declaration)</p> + + + + Major + + + + + + + true + false + readability-redundant-function-ptr-dereference + readability + + true + Redundant Function Ptr Dereference + <p>Finds redundant dereferences of a function pointer.</p> <p>Before:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> f(<span class="dt">int</span>,<span class="dt">int</span>); <span class="dt">int</span> (*p)(<span class="dt">int</span>, <span class="dt">int</span>) = &amp;f; <span class="dt">int</span> i = (**p)(<span class="dv">10</span>, <span class="dv">50</span>);</code></pre></div> <p>After:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> f(<span class="dt">int</span>,<span class="dt">int</span>); <span class="dt">int</span> (*p)(<span class="dt">int</span>, <span class="dt">int</span>) = &amp;f; <span class="dt">int</span> i = (*p)(<span class="dv">10</span>, <span class="dv">50</span>);</code></pre></div> <p>(Clang-Tidy original name: readability-redundant-function-ptr-dereference)</p> + + + + Major + + + + + + + true + false + readability-redundant-member-init + readability + + true + Redundant Member Init + <p>Finds member initializations that are unnecessary because the same default constructor would be called if they were not present.</p> <h5 id="example-16">Example</h5> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Explicitly initializing the member s is unnecessary.</span> <span class="kw">class</span> Foo { <span class="kw">public</span>: Foo() : s() {} <span class="kw">private</span>: std::string s; };</code></pre></div> <h5 id="options-84">Options</h5> <p>IgnoreBaseInCopyConstructors</p> <p>Default is false.</p> <p>When true, the check will ignore unnecessary base class initializations within copy constructors, since some compilers issue warnings/errors when base classes are not explicitly intialized in copy constructors. For example, gcc with -Wextra or -Werror=extra issues warning or error base class 'Bar' should be explicitly initialized in the copy constructor if Bar() were removed in the following example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Explicitly initializing member s and base class Bar is unnecessary.</span> <span class="kw">struct</span> Foo : <span class="kw">public</span> Bar { <span class="co">// Remove s() below. If IgnoreBaseInCopyConstructors!=0, keep Bar().</span> Foo(<span class="dt">const</span> Foo&amp; foo) : Bar(), s() {} std::string s; };</code></pre></div> <p>(Clang-Tidy original name: readability-redundant-member-init)</p> + + + + Major + + + + + + + true + false + readability-redundant-preprocessor + readability + + true + Redundant Preprocessor + <p>Finds potentially redundant preprocessor directives. At the moment the following cases are detected:</p> <ul> <li>#ifdef .. #endif pairs which are nested inside an outer pair with the same condition. For example:</li> </ul> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#ifdef FOO</span> <span class="ot">#ifdef FOO </span><span class="co">// inner ifdef is considered redundant</span> <span class="dt">void</span> f(); <span class="ot">#endif</span> <span class="ot">#endif</span></code></pre></div> <ul> <li>Same for #ifndef .. #endif pairs. For example:</li> </ul> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#ifndef FOO</span> <span class="ot">#ifndef FOO </span><span class="co">// inner ifndef is considered redundant</span> <span class="dt">void</span> f(); <span class="ot">#endif</span> <span class="ot">#endif</span></code></pre></div> <ul> <li>#ifndef inside an #ifdef with the same condition:</li> </ul> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#ifdef FOO</span> <span class="ot">#ifndef FOO </span><span class="co">// inner ifndef is considered redundant</span> <span class="dt">void</span> f(); <span class="ot">#endif</span> <span class="ot">#endif</span></code></pre></div> <ul> <li>#ifdef inside an #ifndef with the same condition:</li> </ul> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#ifndef FOO</span> <span class="ot">#ifdef FOO </span><span class="co">// inner ifdef is considered redundant</span> <span class="dt">void</span> f(); <span class="ot">#endif</span> <span class="ot">#endif</span></code></pre></div> <ul> <li>#if .. #endif pairs which are nested inside an outer pair with the same condition. For example:</li> </ul> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#define FOO 4</span> <span class="ot">#if FOO == 4</span> <span class="ot">#if FOO == 4 </span><span class="co">// inner if is considered redundant</span> <span class="dt">void</span> f(); <span class="ot">#endif</span> <span class="ot">#endif</span></code></pre></div> <p>(Clang-Tidy original name: readability-redundant-preprocessor)</p> + + + + Major + + + + + + + true + false + readability-redundant-string-cstr + readability + + true + Redundant String Cstr + <p>Finds unnecessary calls to std::string::c_str() and std::string::data().</p> <p>(Clang-Tidy original name: readability-redundant-string-cstr)</p> + + + + Major + + + + + + + true + false + readability-redundant-smartptr-get + readability + + true + Redundant Smartptr Get + <p>Find and remove redundant calls to smart pointer’s .get() method.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">ptr.get()-&gt;Foo() ==&gt; ptr-&gt;Foo() *ptr.get() ==&gt; *ptr *ptr-&gt;get() ==&gt; **ptr <span class="kw">if</span> (ptr.get() == <span class="kw">nullptr</span>) ... =&gt; <span class="kw">if</span> (ptr == <span class="kw">nullptr</span>) ...</code></pre></div> <p>IgnoreMacros</p> <p>If this option is set to true (default is true), the check will not warn about calls inside macros.</p> <p>(Clang-Tidy original name: readability-redundant-smartptr-get)</p> + + + + Major + + + + + + + true + false + readability-redundant-string-init + readability + + true + Redundant String Init + <p>Finds unnecessary string initializations.</p> <h5 id="examples-1">Examples</h5> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// Initializing string with empty string literal is unnecessary.</span> std::string a = <span class="st">&quot;&quot;</span>; std::string b(<span class="st">&quot;&quot;</span>); <span class="co">// becomes</span> std::string a; std::string b; <span class="co">// Initializing a string_view with an empty string literal produces an</span> <span class="co">// instance that compares equal to string_view().</span> std::string_view a = <span class="st">&quot;&quot;</span>; std::string_view b(<span class="st">&quot;&quot;</span>); <span class="co">// becomes</span> std::string_view a; std::string_view b;</code></pre></div> <h5 id="options-11">Options</h5> <p>StringNames</p> <p>Default is ::std::basic_string;::std::basic_string_view.</p> <p>Semicolon-delimited list of class names to apply this check to. By default ::std::basic_string applies to std::string and std::wstring. Set to e.g. ::std::basic_string;llvm::StringRef;QString to perform this check on custom classes.</p> <p>(Clang-Tidy original name: readability-redundant-string-init)</p> + + + + Major + + + + + + + true + false + readability-static-accessed-through-instance + readability + + true + Static Accessed Through Instance + <p>Checks for member expressions that access static members through instances, and replaces them with uses of the appropriate qualified-id.</p> <p>Example:</p> <p>The following code:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> C { <span class="dt">static</span> <span class="dt">void</span> foo(); <span class="dt">static</span> <span class="dt">int</span> x; }; C *c1 = <span class="kw">new</span> C(); c1-&gt;foo(); c1-&gt;x;</code></pre></div> <p>is changed to:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">C *c1 = <span class="kw">new</span> C(); C::foo(); C::x;</code></pre></div> <p>(Clang-Tidy original name: readability-static-accessed-through-instance)</p> + + + + Major + + + + + + + true + false + readability-simplify-boolean-expr + readability + + true + Simplify Boolean Expr + <p>Looks for boolean expressions involving boolean constants and simplifies them to use the appropriate boolean expression directly.</p> <p>Examples:</p> <table> <thead> <tr class="header"> <th align="left">Initial expression</th> <th align="left">Result</th> </tr> </thead> <tbody> <tr class="odd"> <td align="left">if (b == true)</td> <td align="left">if (b)</td> </tr> <tr class="even"> <td align="left">if (b == false)</td> <td align="left">if (!b)</td> </tr> <tr class="odd"> <td align="left">if (b &amp;&amp; true)</td> <td align="left">if (b)</td> </tr> <tr class="even"> <td align="left">if (b &amp;&amp; false)</td> <td align="left">if (false)</td> </tr> <tr class="odd"> <td align="left">if (b</td> <td align="left"></td> </tr> <tr class="even"> <td align="left">if (b</td> <td align="left"></td> </tr> <tr class="odd"> <td align="left">e ? true : false</td> <td align="left">e</td> </tr> <tr class="even"> <td align="left">e ? false : true</td> <td align="left">!e</td> </tr> <tr class="odd"> <td align="left">if (true) t(); else f();</td> <td align="left">t();</td> </tr> <tr class="even"> <td align="left">if (false) t(); else f();</td> <td align="left">f();</td> </tr> <tr class="odd"> <td align="left">if (e) return true; else return false;</td> <td align="left">return e;</td> </tr> <tr class="even"> <td align="left">if (e) return false; else return true;</td> <td align="left">return !e;</td> </tr> <tr class="odd"> <td align="left">if (e) b = true; else b = false;</td> <td align="left">b = e;</td> </tr> <tr class="even"> <td align="left">if (e) b = false; else b = true;</td> <td align="left">b = !e;</td> </tr> <tr class="odd"> <td align="left">if (e) return true; return false;</td> <td align="left">return e;</td> </tr> <tr class="even"> <td align="left">if (e) return false; return true;</td> <td align="left">return !e;</td> </tr> </tbody> </table> <p>The resulting expression e is modified as follows:</p> <ol style="list-style-type: decimal"> <li>Unnecessary parentheses around the expression are removed.</li> <li>Negated applications of ! are eliminated.</li> <li>Negated applications of comparison operators are changed to use the opposite condition.</li> <li>Implicit conversions of pointers, including pointers to members, to bool are replaced with explicit comparisons to nullptr in C++11 or NULL in C++98/03.</li> <li>Implicit casts to bool are replaced with explicit casts to bool.</li> <li>Object expressions with explicit operator bool conversion operators are replaced with explicit casts to bool.</li> <li>Implicit conversions of integral types to bool are replaced with explicit comparisons to 0.</li> </ol> <p>Examples:</p> <ol style="list-style-type: decimal"> <li><p>The ternary assignment bool b = (i &lt; 0) ? true : false; has redundant parentheses and becomes bool b = i &lt; 0;.</p></li> <li><p>The conditional return if (!b) return false; return true; has an implied double negation and becomes return b;.</p></li> <li><p>The conditional return if (i &lt; 0) return false; return true; becomes return i &gt;= 0;.</p></li> </ol> <p>The conditional return if (i != 0) return false; return true; becomes return i == 0;.</p> <ol start="4" style="list-style-type: decimal"> <li>The conditional return if (p) return true; return false; has an implicit conversion of a pointer to bool and becomes return p != nullptr;.</li> </ol> <p>The ternary assignment bool b = (i &amp; 1) ? true : false; has an implicit conversion of i &amp; 1 to bool and becomes bool b = (i &amp; 1) != 0;.</p> <ol start="5" style="list-style-type: decimal"> <li><p>The conditional return if (i &amp; 1) return true; else return false; has an implicit conversion of an integer quantity i &amp; 1 to bool and becomes return (i &amp; 1) != 0;</p></li> <li><p>Given struct X { explicit operator bool(); };, and an instance x of struct X, the conditional return if (x) return true; return false; becomes return static_cast<bool>(x);</p></li> </ol> <h5 id="options-24">Options</h5> <p>ChainedConditionalReturn</p> <p>If true, conditional boolean return statements at the end of an if/else if chain will be transformed. Default is false.</p> <p>ChainedConditionalAssignment</p> <p>If true, conditional boolean assignments at the end of an if/else if chain will be transformed. Default is false.</p> <p>(Clang-Tidy original name: readability-simplify-boolean-expr)</p> + + + + Major + + + + + + + true + false + readability-string-compare + readability + + true + String Compare + <p>Finds string comparisons using the compare method.</p> <p>A common mistake is to use the string’s compare method instead of using the equality or inequality operators. The compare method is intended for sorting functions and thus returns a negative number, a positive number or zero depending on the lexicographical relationship between the strings compared. If an equality or inequality check can suffice, that is recommended. This is recommended to avoid the risk of incorrect interpretation of the return value and to simplify the code. The string equality and inequality operators can also be faster than the compare method due to early termination.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::string str1{<span class="st">&quot;a&quot;</span>}; std::string str2{<span class="st">&quot;b&quot;</span>}; <span class="co">// use str1 != str2 instead.</span> <span class="kw">if</span> (str1.compare(str2)) { } <span class="co">// use str1 == str2 instead.</span> <span class="kw">if</span> (!str1.compare(str2)) { } <span class="co">// use str1 == str2 instead.</span> <span class="kw">if</span> (str1.compare(str2) == <span class="dv">0</span>) { } <span class="co">// use str1 != str2 instead.</span> <span class="kw">if</span> (str1.compare(str2) != <span class="dv">0</span>) { } <span class="co">// use str1 == str2 instead.</span> <span class="kw">if</span> (<span class="dv">0</span> == str1.compare(str2)) { } <span class="co">// use str1 != str2 instead.</span> <span class="kw">if</span> (<span class="dv">0</span> != str1.compare(str2)) { } <span class="co">// Use str1 == &quot;foo&quot; instead.</span> <span class="kw">if</span> (str1.compare(<span class="st">&quot;foo&quot;</span>) == <span class="dv">0</span>) { }</code></pre></div> <p>The above code examples shows the list of if-statements that this check will give a warning for. All of them uses compare to check if equality or inequality of two strings instead of using the correct operators.</p> <p>(Clang-Tidy original name: readability-string-compare)</p> + + + + Major + + + + + + + true + false + readability-static-definition-in-anonymous-namespace + readability + + true + Static Definition In Anonymous Namespace + <p>Finds static function and variable definitions in anonymous namespace.</p> <p>In this case, static is redundant, because anonymous namespace limits the visibility of definitions to a single translation unit.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">namespace</span> { <span class="dt">static</span> <span class="dt">int</span> a = <span class="dv">1</span>; <span class="co">// Warning.</span> <span class="dt">static</span> <span class="dt">const</span> b = <span class="dv">1</span>; <span class="co">// Warning.</span> }</code></pre></div> <p>The check will apply a fix by removing the redundant static qualifier.</p> <p>(Clang-Tidy original name: readability-static-definition-in-anonymous-namespace)</p> + + + + Major + + + + + + + true + false + readability-simplify-subscript-expr + readability + + true + Simplify Subscript Expr + <p>This check simplifies subscript expressions. Currently this covers calling .data() and immediately doing an array subscript operation to obtain a single element, in which case simply calling operator[] suffice.</p> <p>Examples:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::string s = ...; <span class="dt">char</span> c = s.data()[i]; <span class="co">// char c = s[i];</span></code></pre></div> <h5 id="options-29">Options</h5> <p>Types</p> <p>The list of type(s) that triggers this check. Default is ::std::basic_string;::std::basic_string_view;::std::vector;::std::array</p> <p>(Clang-Tidy original name: readability-simplify-subscript-expr)</p> + + + + Major + + + + + + + true + false + readability-use-anyofallof + readability + + true + Use Anyofallof + <p>Finds range-based for loops that can be replaced by a call to std::any_of or std::all_of. In C++ 20 mode, suggests std::ranges::any_of or std::ranges::all_of.</p> <p>Example:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">bool</span> all_even(std::vector&lt;<span class="dt">int</span>&gt; V) { <span class="kw">for</span> (<span class="dt">int</span> I : V) { <span class="kw">if</span> (I % <span class="dv">2</span>) <span class="kw">return</span> <span class="kw">false</span>; } <span class="kw">return</span> <span class="kw">true</span>; <span class="co">// Replace loop by</span> <span class="co">// return std::ranges::all_of(V, [](int I) { return I % 2 == 0; });</span> }</code></pre></div> <p>(Clang-Tidy original name: readability-use-anyofallof)</p> + + + + Major + + + + + + + true + false + readability-uniqueptr-delete-release + readability + + true + Uniqueptr Delete Release + <p>Replace delete <unique_ptr>.release() with <unique_ptr> = nullptr. The latter is shorter, simpler and does not require use of raw pointer APIs.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">std::unique_ptr&lt;<span class="dt">int</span>&gt; P; <span class="kw">delete</span> P.release(); <span class="co">// becomes</span> std::unique_ptr&lt;<span class="dt">int</span>&gt; P; P = <span class="kw">nullptr</span>;</code></pre></div> <p>(Clang-Tidy original name: readability-uniqueptr-delete-release)</p> + + + + Major + + + + + + + true + false + readability-uppercase-literal-suffix + readability + + true + Uppercase Literal Suffix + <p>cert-dcl16-c redirects here as an alias for this check. By default, only the suffixes that begin with l (l, ll, lu, llu, but not u, ul, ull) are diagnosed by that alias.</p> <p>hicpp-uppercase-literal-suffix redirects here as an alias for this check.</p> <p>Detects when the integral literal or floating point (decimal or hexadecimal) literal has a non-uppercase suffix and provides a fix-it hint with the uppercase suffix.</p> <p>All valid combinations of suffixes are supported.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">auto</span> x = <span class="dv">1</span>; <span class="co">// OK, no suffix.</span> <span class="kw">auto</span> x = <span class="dv">1u</span>; <span class="co">// warning: integer literal suffix &#39;u&#39; is not upper-case</span> <span class="kw">auto</span> x = <span class="dv">1U</span>; <span class="co">// OK, suffix is uppercase.</span> ...</code></pre></div> <h5 id="options-53">Options</h5> <p>NewSuffixes</p> <p>Optionally, a list of the destination suffixes can be provided. When the suffix is found, a case-insensitive lookup in that list is made, and if a replacement is found that is different from the current suffix, then the diagnostic is issued. This allows for fine-grained control of what suffixes to consider and what their replacements should be.</p> <h6 id="example-4">Example</h6> <p>Given a list L;uL:</p> <ul> <li>l -&gt; L</li> <li>L will be kept as is.</li> <li>ul -&gt; uL</li> <li>Ul -&gt; uL</li> <li>UL -&gt; uL</li> <li>uL will be kept as is.</li> <li>ull will be kept as is, since it is not in the list</li> <li>and so on.</li> </ul> <p>IgnoreMacros</p> <p>If this option is set to true (default is true), the check will not warn about literal suffixes inside macros.</p> <p>(Clang-Tidy original name: readability-uppercase-literal-suffix)</p> + + + + Major + + + + + + + true + false + clang-analyzer-core.builtin.BuiltinFunctions + clang-analyzer-core.builtin + + true + Builtin Functions + + + + Major + + + + + + + true + false + clang-analyzer-core.builtin.NoReturnFunctions + clang-analyzer-core.builtin + + true + No Return Functions + + + + Major + + + + + + + true + false + clang-analyzer-core.CallAndMessage + clang-analyzer-core + + true + Call And Message + <p>Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers).</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">//C</span> <span class="dt">void</span> test() { <span class="dt">void</span> (*foo)(<span class="dt">void</span>); foo = <span class="dv">0</span>; foo(); <span class="co">// warn: function pointer is null</span> } <span class="co">// C++</span> <span class="kw">class</span> C { <span class="kw">public</span>: <span class="dt">void</span> f(); }; <span class="dt">void</span> test() { C *pc; pc-&gt;f(); <span class="co">// warn: object pointer is uninitialized</span> } <span class="co">// C++</span> <span class="kw">class</span> C { <span class="kw">public</span>: <span class="dt">void</span> f(); }; <span class="dt">void</span> test() { C *pc = <span class="dv">0</span>; pc-&gt;f(); <span class="co">// warn: object pointer is null</span> } <span class="co">// Objective-C</span> <span class="er">@</span>interface MyClass : NSObject <span class="er">@</span>property (readwrite,assign) id x; - (<span class="dt">long</span> <span class="dt">double</span>)longDoubleM; <span class="er">@</span>end <span class="dt">void</span> test() { MyClass *obj1; <span class="dt">long</span> <span class="dt">double</span> ld1 = [obj1 longDoubleM]; <span class="co">// warn: receiver is uninitialized</span> } <span class="co">// Objective-C</span> <span class="er">@</span>interface MyClass : NSObject <span class="er">@</span>property (readwrite,assign) id x; - (<span class="dt">long</span> <span class="dt">double</span>)longDoubleM; <span class="er">@</span>end <span class="dt">void</span> test() { MyClass *obj1; id i = obj1.x; <span class="co">// warn: uninitialized object pointer</span> } <span class="co">// Objective-C</span> <span class="er">@</span>interface Subscriptable : NSObject - (id)objectAtIndexedSubscript:(<span class="dt">unsigned</span> <span class="dt">int</span>)index; <span class="er">@</span>end <span class="er">@</span>interface MyClass : Subscriptable <span class="er">@</span>property (readwrite,assign) id x; - (<span class="dt">long</span> <span class="dt">double</span>)longDoubleM; <span class="er">@</span>end <span class="dt">void</span> test() { MyClass *obj1; id i = obj1[<span class="dv">0</span>]; <span class="co">// warn: uninitialized object pointer</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-core.CallAndMessage)</p> + + + + Major + + + + + + + true + false + clang-analyzer-core.DynamicTypePropagation + clang-analyzer-core + + true + Dynamic Type Propagation + + + + Major + + + + + + + true + false + clang-analyzer-core.DivideZero + clang-analyzer-core + + true + Divide Zero + <p>Check for division by zero.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test(<span class="dt">int</span> z) { <span class="kw">if</span> (z == <span class="dv">0</span>) <span class="dt">int</span> x = <span class="dv">1</span> / z; <span class="co">// warn</span> } <span class="dt">void</span> test() { <span class="dt">int</span> x = <span class="dv">1</span>; <span class="dt">int</span> y = x % <span class="dv">0</span>; <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-core.DivideZero)</p> + + + + Major + + + + + + + true + false + clang-analyzer-core.NullDereference + clang-analyzer-core + + true + Null Dereference + <p>Check for dereferences of null pointers.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// C</span> <span class="dt">void</span> test(<span class="dt">int</span> *p) { <span class="kw">if</span> (p) <span class="kw">return</span>; <span class="dt">int</span> x = p[<span class="dv">0</span>]; <span class="co">// warn</span> } <span class="co">// C</span> <span class="dt">void</span> test(<span class="dt">int</span> *p) { <span class="kw">if</span> (!p) *p = <span class="dv">0</span>; <span class="co">// warn</span> } <span class="co">// C++</span> <span class="kw">class</span> C { <span class="kw">public</span>: <span class="dt">int</span> x; }; <span class="dt">void</span> test() { C *pc = <span class="dv">0</span>; <span class="dt">int</span> k = pc-&gt;x; <span class="co">// warn</span> } <span class="co">// Objective-C</span> <span class="er">@</span>interface MyClass { <span class="er">@</span>public <span class="dt">int</span> x; } <span class="er">@</span>end <span class="dt">void</span> test() { MyClass *obj = <span class="dv">0</span>; obj-&gt;x = <span class="dv">1</span>; <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-core.NullDereference)</p> + + + + Major + + + + + + + true + false + clang-analyzer-core.NonNullParamChecker + clang-analyzer-core + + true + Non Null Param Checker + <p>Check for null pointers passed as arguments to a function whose arguments are references or marked with the ‘nonnull’ attribute.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> f(<span class="dt">int</span> *p) <span class="ot">__attribute__</span>((nonnull)); <span class="dt">void</span> test(<span class="dt">int</span> *p) { <span class="kw">if</span> (!p) f(p); <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-core.NonNullParamChecker)</p> + + + + Major + + + + + + + true + false + clang-analyzer-core.NonnilStringConstants + clang-analyzer-core + + true + Non Nil String Constants + + + + Major + + + + + + + true + false + clang-analyzer-core.StackAddressEscape + clang-analyzer-core + + true + Stack Address Escape + <p>Check that addresses to stack memory do not escape the function.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">char</span> <span class="dt">const</span> *p; <span class="dt">void</span> test() { <span class="dt">char</span> <span class="dt">const</span> str[] = <span class="st">&quot;string&quot;</span>; p = str; <span class="co">// warn</span> } <span class="dt">void</span>* test() { <span class="kw">return</span> <span class="ot">__builtin_alloca</span>(<span class="dv">12</span>); <span class="co">// warn</span> } <span class="dt">void</span> test() { <span class="dt">static</span> <span class="dt">int</span> *x; <span class="dt">int</span> y; x = &amp;y; <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-core.StackAddressEscape)</p> + + + + Major + + + + + + + true + false + clang-analyzer-core.StackAddrEscapeBase + clang-analyzer-core + + true + Stack Address Escape Base + + + + Major + + + + + + + true + false + clang-analyzer-core.UndefinedBinaryOperatorResult + clang-analyzer-core + + true + Undefined Binary Operator Result + <p>Check for undefined results of binary operators.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { <span class="dt">int</span> x; <span class="dt">int</span> y = x + <span class="dv">1</span>; <span class="co">// warn: left operand is garbage</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-core.UndefinedBinaryOperatorResult)</p> + + + + Major + + + + + + + true + false + clang-analyzer-core.VLASize + clang-analyzer-core + + true + VLA Size + <p>Check for declarations of Variable Length Arrays of undefined or zero size.</p> <p>Check for declarations of VLA of undefined or zero size.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { <span class="dt">int</span> x; <span class="dt">int</span> vla1[x]; <span class="co">// warn: garbage as size</span> } <span class="dt">void</span> test() { <span class="dt">int</span> x = <span class="dv">0</span>; <span class="dt">int</span> vla2[x]; <span class="co">// warn: zero size</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-core.VLASize)</p> + + + + Major + + + + + + + true + false + clang-analyzer-cplusplus.InnerPointer + clang-analyzer-cplusplus + + true + Inner Pointer + <p>Check for inner pointers of C++ containers used after re/deallocation.</p> <p>Many container methods in the C++ standard library are known to invalidate “references” (including actual references, iterators and raw pointers) to elements of the container. Using such references after they are invalidated causes undefined behavior, which is a common source of memory errors in C++ that this checker is capable of finding.</p> <p>The checker is currently limited to std::string objects and doesn’t recognize some of the more sophisticated approaches to passing unowned pointers around, such as std::string_view.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> deref_after_assignment() { std::string s = <span class="st">&quot;llvm&quot;</span>; <span class="dt">const</span> <span class="dt">char</span> *c = s.data(); <span class="co">// note: pointer to inner buffer of &#39;std::string&#39; obtained here</span> s = <span class="st">&quot;clang&quot;</span>; <span class="co">// note: inner buffer of &#39;std::string&#39; reallocated by call to &#39;operator=&#39;</span> consume(c); <span class="co">// warn: inner pointer of container used after re/deallocation</span> } <span class="dt">const</span> <span class="dt">char</span> *return_temp(<span class="dt">int</span> x) { <span class="kw">return</span> std::to_string(x).c_str(); <span class="co">// warn: inner pointer of container used after re/deallocation</span> <span class="co">// note: pointer to inner buffer of &#39;std::string&#39; obtained here</span> <span class="co">// note: inner buffer of &#39;std::string&#39; deallocated by call to destructor</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-cplusplus.InnerPointer)</p> + + + + Major + + + + + + + true + false + clang-analyzer-cplusplus.Move + clang-analyzer-cplusplus + + true + Move + + + + Major + + + + + + + true + false + clang-analyzer-cplusplus.NewDelete + clang-analyzer-cplusplus + + true + New Delete + <p>Check for double-free and use-after-free problems. Traces memory managed by new/delete.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> f(<span class="dt">int</span> *p); <span class="dt">void</span> testUseMiddleArgAfterDelete(<span class="dt">int</span> *p) { <span class="kw">delete</span> p; f(p); <span class="co">// warn: use after free</span> } <span class="kw">class</span> SomeClass { <span class="kw">public</span>: <span class="dt">void</span> f(); }; <span class="dt">void</span> test() { SomeClass *c = <span class="kw">new</span> SomeClass; <span class="kw">delete</span> c; c-&gt;f(); <span class="co">// warn: use after free</span> } <span class="dt">void</span> test() { <span class="dt">int</span> *p = (<span class="dt">int</span> *)<span class="ot">__builtin_alloca</span>(<span class="kw">sizeof</span>(<span class="dt">int</span>)); <span class="kw">delete</span> p; <span class="co">// warn: deleting memory allocated by alloca</span> } <span class="dt">void</span> test() { <span class="dt">int</span> *p = <span class="kw">new</span> <span class="dt">int</span>; <span class="kw">delete</span> p; <span class="kw">delete</span> p; <span class="co">// warn: attempt to free released</span> } <span class="dt">void</span> test() { <span class="dt">int</span> i; <span class="kw">delete</span> &amp;i; <span class="co">// warn: delete address of local</span> } <span class="dt">void</span> test() { <span class="dt">int</span> *p = <span class="kw">new</span> <span class="dt">int</span>[<span class="dv">1</span>]; <span class="kw">delete</span>[] (++p); <span class="co">// warn: argument to &#39;delete[]&#39; is offset by 4 bytes</span> <span class="co">// from the start of memory allocated by &#39;new[]&#39;</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-cplusplus.NewDelete)</p> + + + + Major + + + + + + + true + false + clang-analyzer-cplusplus.NewDeleteLeaks + clang-analyzer-cplusplus + + true + New Delete Leaks + <p>Check for memory leaks. Traces memory managed by new/delete.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { <span class="dt">int</span> *p = <span class="kw">new</span> <span class="dt">int</span>; } <span class="co">// warn</span></code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-cplusplus.NewDeleteLeaks)</p> + + + + Major + + + + + + + true + false + clang-analyzer-cplusplus.PlacementNew + clang-analyzer-cplusplus + + true + Placement New Checker + <p>Check if default placement new is provided with pointers to sufficient storage capacity.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="ot">#include &lt;new&gt;</span> <span class="dt">void</span> f() { <span class="dt">short</span> s; <span class="dt">long</span> *lp = ::<span class="kw">new</span> (&amp;s) <span class="dt">long</span>; <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-cplusplus.PlacementNew)</p> + + + + Major + + + + + + + true + false + clang-analyzer-cplusplus.PureVirtualCall + clang-analyzer-cplusplus + + true + Pure Virtual Call + + + + Major + + + + + + + true + false + clang-analyzer-cplusplus.SelfAssignment + clang-analyzer-cplusplus + + true + Self Assignment + <p>Checks C++ copy and move assignment operators for self assignment.</p> <p>(Clang-Tidy original name: clang-analyzer-cplusplus.SelfAssignment)</p> + + + + Major + + + + + + + true + false + clang-analyzer-deadcode.DeadStores + clang-analyzer-deadcode + + true + Dead Stores + <p>Check for values stored to variables that are never read afterwards.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { <span class="dt">int</span> x; x = <span class="dv">1</span>; <span class="co">// warn</span> }</code></pre></div> <p>The WarnForDeadNestedAssignments option enables the checker to emit warnings for nested dead assignments. You can disable with the -analyzer-config deadcode.DeadStores:WarnForDeadNestedAssignments=false. <em>Defaults to true</em>.</p> <p>Would warn for this e.g.: if ((y = make_int())) { }</p> <p>(Clang-Tidy original name: clang-analyzer-deadcode.DeadStores)</p> + + + + Major + + + + + + + false + false + clang-analyzer-fuchsia.HandleChecker + clang-analyzer-fuchsia + + true + Handle Checker + <p>Handles identify resources. Similar to pointers they can be leaked, double freed, or use after freed. This check attempts to find such problems.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> checkLeak08(<span class="dt">int</span> tag) { zx_handle_t sa, sb; zx_channel_create(<span class="dv">0</span>, &amp;sa, &amp;sb); <span class="kw">if</span> (tag) zx_handle_close(sa); use(sb); <span class="co">// Warn: Potential leak of handle</span> zx_handle_close(sb); }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-fuchsia.HandleChecker)</p> + + + + Major + + + + + + + true + false + clang-analyzer-nullability.NullabilityBase + clang-analyzer-nullability + + true + Nullability Base + + + + Major + + + + + + + true + false + clang-analyzer-nullability.NullableDereferenced + clang-analyzer-nullability + + true + Nullable Dereferenced + <p>Warns when a nullable pointer is dereferenced.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> LinkedList { <span class="dt">int</span> data; <span class="kw">struct</span> LinkedList *next; }; <span class="kw">struct</span> LinkedList * _Nullable getNext(<span class="kw">struct</span> LinkedList *l); <span class="dt">void</span> updateNextData(<span class="kw">struct</span> LinkedList *list, <span class="dt">int</span> newData) { <span class="kw">struct</span> LinkedList *next = getNext(list); <span class="co">// Warning: Nullable pointer is dereferenced</span> next-&gt;data = <span class="dv">7</span>; }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-nullability.NullableDereferenced)</p> + + + + Major + + + + + + + true + false + clang-analyzer-nullability.NullablePassedToNonnull + clang-analyzer-nullability + + true + Nullable Passed To Nonnull + <p>Warns when a nullable pointer is passed to a pointer which has a _Nonnull type.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">typedef</span> <span class="kw">struct</span> Dummy { <span class="dt">int</span> val; } Dummy; Dummy *_Nullable returnsNullable(); <span class="dt">void</span> takesNonnull(Dummy *_Nonnull); <span class="dt">void</span> test() { Dummy *p = returnsNullable(); takesNonnull(p); <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-nullability.NullablePassedToNonnull)</p> + + + + Major + + + + + + + true + false + clang-analyzer-nullability.NullPassedToNonnull + clang-analyzer-nullability + + true + Null Passed To Nonnull + <p>Warns when a null pointer is passed to a pointer which has a _Nonnull type.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">if</span> (name != nil) <span class="kw">return</span>; <span class="co">// Warning: nil passed to a callee that requires a non-null 1st parameter</span> NSString *greeting = [<span class="er">@</span><span class="st">&quot;Hello &quot;</span> stringByAppendingString:name];</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-nullability.NullPassedToNonnull)</p> + + + + Major + + + + + + + true + false + clang-analyzer-nullability.NullableReturnedFromNonnull + clang-analyzer-nullability + + true + Nullable Returned From Nonnull + <p>Warns when a nullable pointer is returned from a function that has _Nonnull return type.</p> <p>(Clang-Tidy original name: clang-analyzer-nullability.NullableReturnedFromNonnull)</p> + + + + Major + + + + + + + true + false + clang-analyzer-nullability.NullReturnedFromNonnull + clang-analyzer-nullability + + true + Null Returned From Nonnull + <p>Warns when a null pointer is returned from a function that has _Nonnull return type.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">- (nonnull id)firstChild { id result = nil; <span class="kw">if</span> ([_children count] &gt; <span class="dv">0</span>) result = _children[<span class="dv">0</span>]; <span class="co">// Warning: nil returned from a method that is expected</span> <span class="co">// to return a non-null value</span> <span class="kw">return</span> result; }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-nullability.NullReturnedFromNonnull)</p> + + + + Major + + + + + + + true + false + clang-analyzer-optin.cplusplus.UninitializedObject + clang-analyzer-optin.cplusplus + + true + Uninitialized Object + <p>This checker reports uninitialized fields in objects created after a constructor call. It doesn’t only find direct uninitialized fields, but rather makes a deep inspection of the object, analyzing all of it’s fields subfields. The checker regards inherited fields as direct fields, so one will receive warnings for uninitialized inherited data members as well.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// With Pedantic and CheckPointeeInitialization set to true</span> <span class="kw">struct</span> A { <span class="kw">struct</span> B { <span class="dt">int</span> x; <span class="co">// note: uninitialized field &#39;this-&gt;b.x&#39;</span> <span class="co">// note: uninitialized field &#39;this-&gt;bptr-&gt;x&#39;</span> <span class="dt">int</span> y; <span class="co">// note: uninitialized field &#39;this-&gt;b.y&#39;</span> <span class="co">// note: uninitialized field &#39;this-&gt;bptr-&gt;y&#39;</span> }; <span class="dt">int</span> *iptr; <span class="co">// note: uninitialized pointer &#39;this-&gt;iptr&#39;</span> B b; B *bptr; <span class="dt">char</span> *cptr; <span class="co">// note: uninitialized pointee &#39;this-&gt;cptr&#39;</span> A (B *bptr, <span class="dt">char</span> *cptr) : bptr(bptr), cptr(cptr) {} }; <span class="dt">void</span> f() { A::B b; <span class="dt">char</span> c; A a(&amp;b, &amp;c); <span class="co">// warning: 6 uninitialized fields</span> <span class="co">// after the constructor call</span> } <span class="co">// With Pedantic set to false and</span> <span class="co">// CheckPointeeInitialization set to true</span> <span class="co">// (every field is uninitialized)</span> <span class="kw">struct</span> A { <span class="kw">struct</span> B { <span class="dt">int</span> x; <span class="dt">int</span> y; }; <span class="dt">int</span> *iptr; B b; B *bptr; <span class="dt">char</span> *cptr; A (B *bptr, <span class="dt">char</span> *cptr) : bptr(bptr), cptr(cptr) {} }; <span class="dt">void</span> f() { A::B b; <span class="dt">char</span> c; A a(&amp;b, &amp;c); <span class="co">// no warning</span> } <span class="co">// With Pedantic set to true and</span> <span class="co">// CheckPointeeInitialization set to false</span> <span class="co">// (pointees are regarded as initialized)</span> <span class="kw">struct</span> A { <span class="kw">struct</span> B { <span class="dt">int</span> x; <span class="co">// note: uninitialized field &#39;this-&gt;b.x&#39;</span> <span class="dt">int</span> y; <span class="co">// note: uninitialized field &#39;this-&gt;b.y&#39;</span> }; <span class="dt">int</span> *iptr; <span class="co">// note: uninitialized pointer &#39;this-&gt;iptr&#39;</span> B b; B *bptr; <span class="dt">char</span> *cptr; A (B *bptr, <span class="dt">char</span> *cptr) : bptr(bptr), cptr(cptr) {} }; <span class="dt">void</span> f() { A::B b; <span class="dt">char</span> c; A a(&amp;b, &amp;c); <span class="co">// warning: 3 uninitialized fields</span> <span class="co">// after the constructor call</span> }</code></pre></div> <p><strong>Options</strong></p> <p>This checker has several options which can be set from command line (e.g. -analyzer-config optin.cplusplus.UninitializedObject:Pedantic=true):</p> <ul> <li>Pedantic (boolean). If to false, the checker won’t emit warnings for objects that don’t have at least one initialized field. Defaults to false.</li> <li>NotesAsWarnings (boolean). If set to true, the checker will emit a warning for each uninitialized field, as opposed to emitting one warning per constructor call, and listing the uninitialized fields that belongs to it in notes. <em>Defaults to false</em>.</li> <li>CheckPointeeInitialization (boolean). If set to false, the checker will not analyze the pointee of pointer/reference fields, and will only check whether the object itself is initialized. <em>Defaults to false</em>.</li> <li>IgnoreRecordsWithField (string). If supplied, the checker will not analyze structures that have a field with a name or type name that matches the given pattern. <em>Defaults to “”</em>.</li> </ul> <p>(Clang-Tidy original name: clang-analyzer-optin.cplusplus.UninitializedObject)</p> + + + + Major + + + + + + + true + false + clang-analyzer-optin.cplusplus.VirtualCall + clang-analyzer-optin.cplusplus + + true + Virtual Call + <p>Check virtual function calls during construction or destruction.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> A { <span class="kw">public</span>: A() { f(); <span class="co">// warn</span> } <span class="kw">virtual</span> <span class="dt">void</span> f(); }; <span class="kw">class</span> A { <span class="kw">public</span>: ~A() { <span class="kw">this</span>-&gt;f(); <span class="co">// warn</span> } <span class="kw">virtual</span> <span class="dt">void</span> f(); };</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-optin.cplusplus.VirtualCall)</p> + + + + Major + + + + + + + true + false + clang-analyzer-optin.mpi.MPI-Checker + clang-analyzer-optin.mpi + + true + MPI-Checker + <p>Checks MPI code.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { <span class="dt">double</span> buf = <span class="dv">0</span>; MPI_Request sendReq1; MPI_Ireduce(MPI_IN_PLACE, &amp;buf, <span class="dv">1</span>, MPI_DOUBLE, MPI_SUM, <span class="dv">0</span>, MPI_COMM_WORLD, &amp;sendReq1); } <span class="co">// warn: request &#39;sendReq1&#39; has no matching wait.</span> <span class="dt">void</span> test() { <span class="dt">double</span> buf = <span class="dv">0</span>; MPI_Request sendReq; MPI_Isend(&amp;buf, <span class="dv">1</span>, MPI_DOUBLE, <span class="dv">0</span>, <span class="dv">0</span>, MPI_COMM_WORLD, &amp;sendReq); MPI_Irecv(&amp;buf, <span class="dv">1</span>, MPI_DOUBLE, <span class="dv">0</span>, <span class="dv">0</span>, MPI_COMM_WORLD, &amp;sendReq); <span class="co">// warn</span> MPI_Isend(&amp;buf, <span class="dv">1</span>, MPI_DOUBLE, <span class="dv">0</span>, <span class="dv">0</span>, MPI_COMM_WORLD, &amp;sendReq); <span class="co">// warn</span> MPI_Wait(&amp;sendReq, MPI_STATUS_IGNORE); } <span class="dt">void</span> missingNonBlocking() { <span class="dt">int</span> rank = <span class="dv">0</span>; MPI_Comm_rank(MPI_COMM_WORLD, &amp;rank); MPI_Request sendReq1[<span class="dv">10</span>][<span class="dv">10</span>][<span class="dv">10</span>]; MPI_Wait(&amp;sendReq1[<span class="dv">1</span>][<span class="dv">7</span>][<span class="dv">9</span>], MPI_STATUS_IGNORE); <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-optin.mpi.MPI-Checker)</p> + + + + Major + + + + + + + false + false + clang-analyzer-optin.osx.cocoa.localizability.EmptyLocalizationContextChecker + clang-analyzer-optin.osx.cocoa.localizability + + true + Empty Localization Context Checker + <p>Check that NSLocalizedString macros include a comment for context.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">- (<span class="dt">void</span>)test { NSString *string = NSLocalizedString(<span class="er">@</span><span class="st">&quot;LocalizedString&quot;</span>, nil); <span class="co">// warn</span> NSString *string2 = NSLocalizedString(<span class="er">@</span><span class="st">&quot;LocalizedString&quot;</span>, <span class="er">@</span><span class="st">&quot; &quot;</span>); <span class="co">// warn</span> NSString *string3 = NSLocalizedStringWithDefaultValue( <span class="er">@</span><span class="st">&quot;LocalizedString&quot;</span>, nil, [[<span class="kw">NSBundle</span> <span class="kw">alloc</span>] <span class="kw">init</span>], <span class="kw">nil</span>,<span class="kw">@</span><span class="st">&quot;&quot;</span>); // <span class="kw">warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-optin.osx.cocoa.localizability.EmptyLocalizationContextChecker)</p> + + + + Major + + + + + + + false + false + clang-analyzer-optin.osx.cocoa.localizability.NonLocalizedStringChecker + clang-analyzer-optin.osx.cocoa.localizability + + true + Non Localized String Checker + <p>Warns about uses of non-localized NSStrings passed to UI methods expecting localized NSStrings.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">NSString *alarmText = NSLocalizedString(<span class="er">@</span><span class="st">&quot;Enabled&quot;</span>, <span class="er">@</span><span class="st">&quot;Indicates alarm is turned on&quot;</span>); <span class="kw">if</span> (!isEnabled) { alarmText = <span class="er">@</span><span class="st">&quot;Disabled&quot;</span>; } UILabel *alarmStateLabel = [[<span class="kw">UILabel</span> <span class="kw">alloc</span>] <span class="kw">init</span>]; // <span class="kw">Warning:</span> <span class="kw">User</span>-<span class="kw">facing</span> <span class="kw">text</span> <span class="kw">should</span> <span class="kw">use</span> <span class="kw">localized</span> <span class="kw">string</span> <span class="kw">macro</span> [<span class="kw">alarmStateLabel</span> <span class="kw">setText:alarmText</span>];</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-optin.osx.cocoa.localizability.NonLocalizedStringChecker)</p> + + + + Major + + + + + + + false + false + clang-analyzer-optin.osx.OSObjectCStyleCast + clang-analyzer-optin.osx + + true + OSObject C-Style Cast + + + + Major + + + + + + + true + false + clang-analyzer-optin.performance.GCDAntipattern + clang-analyzer-optin.performance + + true + GCD Antipattern + <p>Check for performance anti-patterns when using Grand Central Dispatch.</p> <p>(Clang-Tidy original name: clang-analyzer-optin.performance.GCDAntipattern)</p> + + + + Major + + + + + + + true + false + clang-analyzer-optin.performance.Padding + clang-analyzer-optin.performance + + true + Padding + <p>Check for excessively padded structs.</p> <p>(Clang-Tidy original name: clang-analyzer-optin.performance.Padding)</p> + + + + Major + + + + + + + true + false + clang-analyzer-optin.portability.UnixAPI + clang-analyzer-optin.portability + + true + Unix API + <p>Finds implementation-defined behavior in UNIX/Posix functions.</p> <p>(Clang-Tidy original name: clang-analyzer-optin.portability.UnixAPI)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.API + clang-analyzer-osx + + true + API + <p>Check for proper uses of various Apple APIs.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { dispatch_once_t pred = <span class="dv">0</span>; dispatch_once(&amp;pred, ^(){}); <span class="co">// warn: dispatch_once uses local</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-osx.API)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.cocoa.AtSync + clang-analyzer-osx.cocoa + + true + At Sync + <p>Check for nil pointers used as mutexes for <span class="citation">@synchronized</span>.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test(id x) { <span class="kw">if</span> (!x) <span class="er">@</span>synchronized(x) {} <span class="co">// warn: nil value used as mutex</span> } <span class="dt">void</span> test() { id y; <span class="er">@</span>synchronized(y) {} <span class="co">// warn: uninitialized value used as mutex</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-osx.cocoa.AtSync)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.cocoa.AutoreleaseWrite + clang-analyzer-osx.cocoa + + true + Autorelease Write + <p>Warn about potentially crashing writes to autoreleasing objects from different autoreleasing pools in Objective-C.</p> <p>(Clang-Tidy original name: clang-analyzer-osx.cocoa.AutoreleaseWrite)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.cocoa.ClassRelease + clang-analyzer-osx.cocoa + + true + Class Release + <p>Check for sending ‘retain’, ‘release’, or ‘autorelease’ directly to a Class.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="er">@</span>interface MyClass : NSObject <span class="er">@</span>end <span class="dt">void</span> test(<span class="dt">void</span>) { [MyClass release]; <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-osx.cocoa.ClassRelease)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.cocoa.Dealloc + clang-analyzer-osx.cocoa + + true + Dealloc + <p>Warn about Objective-C classes that lack a correct implementation of -dealloc</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="er">@</span>interface MyObject : NSObject { id _myproperty; } <span class="er">@</span>end <span class="er">@</span>implementation MyObject <span class="co">// warn: lacks &#39;dealloc&#39;</span> <span class="er">@</span>end <span class="er">@</span>interface MyObject : NSObject {} <span class="er">@</span>property(assign) id myproperty; <span class="er">@</span>end <span class="er">@</span>implementation MyObject <span class="co">// warn: does not send &#39;dealloc&#39; to super</span> - (<span class="dt">void</span>)dealloc { self.myproperty = <span class="dv">0</span>; } <span class="er">@</span>end <span class="er">@</span>interface MyObject : NSObject { id _myproperty; } <span class="er">@</span>property(retain) id myproperty; <span class="er">@</span>end <span class="er">@</span>implementation MyObject <span class="er">@</span>synthesize myproperty = _myproperty; <span class="co">// warn: var was retained but wasn&#39;t released</span> - (<span class="dt">void</span>)dealloc { [super dealloc]; } <span class="er">@</span>end <span class="er">@</span>interface MyObject : NSObject { id _myproperty; } <span class="er">@</span>property(assign) id myproperty; <span class="er">@</span>end <span class="er">@</span>implementation MyObject <span class="er">@</span>synthesize myproperty = _myproperty; <span class="co">// warn: var wasn&#39;t retained but was released</span> - (<span class="dt">void</span>)dealloc { [_myproperty release]; [super dealloc]; } <span class="er">@</span>end</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-osx.cocoa.Dealloc)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.cocoa.IncompatibleMethodTypes + clang-analyzer-osx.cocoa + + true + Incompatible Method Types + <p>Warn about Objective-C method signatures with type incompatibilities.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="er">@</span>interface MyClass1 : NSObject - (<span class="dt">int</span>)foo; <span class="er">@</span>end <span class="er">@</span>implementation MyClass1 - (<span class="dt">int</span>)foo { <span class="kw">return</span> <span class="dv">1</span>; } <span class="er">@</span>end <span class="er">@</span>interface MyClass2 : MyClass1 - (<span class="dt">float</span>)foo; <span class="er">@</span>end <span class="er">@</span>implementation MyClass2 - (<span class="dt">float</span>)foo { <span class="kw">return</span> <span class="fl">1.0</span>; } <span class="co">// warn</span> <span class="er">@</span>end</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-osx.cocoa.IncompatibleMethodTypes)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.cocoa.Loops + clang-analyzer-osx.cocoa + + true + Loops + <p>Improved modeling of loops using Cocoa collection types.</p> <p>(Clang-Tidy original name: clang-analyzer-osx.cocoa.Loops)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.cocoa.MissingSuperCall + clang-analyzer-osx.cocoa + + true + Missing Super Call + <p>Warn about Objective-C methods that lack a necessary call to super.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="er">@</span>interface Test : UIViewController <span class="er">@</span>end <span class="er">@</span>implementation test - (<span class="dt">void</span>)viewDidLoad {} <span class="co">// warn</span> <span class="er">@</span>end</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-osx.cocoa.MissingSuperCall)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.cocoa.NilArg + clang-analyzer-osx.cocoa + + true + Nil Arg + <p>Check for prohibited nil arguments to ObjC method calls.</p> <ul> <li>caseInsensitiveCompare:</li> <li>compare:</li> <li>compare:options:</li> <li>compare:options:range:</li> <li>compare:options:range:locale:</li> <li>componentsSeparatedByCharactersInSet:</li> <li>initWithFormat:</li> </ul> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">NSComparisonResult test(NSString *s) { NSString *aString = nil; <span class="kw">return</span> [s caseInsensitiveCompare:aString]; <span class="co">// warn: argument to &#39;NSString&#39; method</span> <span class="co">// &#39;caseInsensitiveCompare:&#39; cannot be nil</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-osx.cocoa.NilArg)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.cocoa.NSAutoreleasePool + clang-analyzer-osx.cocoa + + true + NS Autorelease Pool + <p>Warn for suboptimal uses of NSAutoreleasePool in Objective-C GC mode.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { NSAutoreleasePool *pool = [[<span class="kw">NSAutoreleasePool</span> <span class="kw">alloc</span>] <span class="kw">init</span>]; [<span class="kw">pool</span> <span class="kw">release</span>]; // <span class="kw">warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-osx.cocoa.NSAutoreleasePool)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.cocoa.NSError + clang-analyzer-osx.cocoa + + true + NS Error + <p>Check usage of NSError parameters.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="er">@</span>interface A : NSObject - (<span class="dt">void</span>)foo:(NSError <span class="st">&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;</span>)error; <span class="er">@</span>end <span class="er">@</span>implementation A - (<span class="dt">void</span>)foo:(NSError <span class="st">&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;</span>)error { <span class="co">// warn: method accepting NSError&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot; should have a non-void</span> <span class="co">// return value</span> } <span class="er">@</span>end <span class="er">@</span>interface A : NSObject - (BOOL)foo:(NSError <span class="st">&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;</span>)error; <span class="er">@</span>end <span class="er">@</span>implementation A - (BOOL)foo:(NSError <span class="st">&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;</span>)error { *error = <span class="dv">0</span>; <span class="co">// warn: potential null dereference</span> <span class="kw">return</span> <span class="dv">0</span>; } <span class="er">@</span>end</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-osx.cocoa.NSError)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.cocoa.NonNilReturnValue + clang-analyzer-osx.cocoa + + true + Non Nil Return Value + <p>Models the APIs that are guaranteed to return a non-nil value.</p> <p>(Clang-Tidy original name: clang-analyzer-osx.cocoa.NonNilReturnValue)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.cocoa.ObjCGenerics + clang-analyzer-osx.cocoa + + true + Obj C Generics + <p>Check for type errors when using Objective-C generics.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">NSMutableArray *names = [NSMutableArray array]; NSMutableArray *birthDates = names; <span class="co">// Warning: Conversion from value of type &#39;NSDate *&#39;</span> <span class="co">// to incompatible type &#39;NSString *&#39;</span> [birthDates addObject: [NSDate date]];</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-osx.cocoa.ObjCGenerics)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.cocoa.RetainCount + clang-analyzer-osx.cocoa + + true + Retain Count + <p>Check for leaks and improper reference count management</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { NSString *s = [[<span class="kw">NSString</span> <span class="kw">alloc</span>] <span class="kw">init</span>]; // <span class="kw">warn</span> } <span class="kw">CFStringRef</span> <span class="kw">test</span>(<span class="kw">char</span> *<span class="kw">bytes</span>) { <span class="kw">return</span> <span class="kw">CFStringCreateWithCStringNoCopy</span>( <span class="kw">0</span>, <span class="kw">bytes</span>, <span class="kw">NSNEXTSTEPStringEncoding</span>, <span class="kw">0</span>); // <span class="kw">warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-osx.cocoa.RetainCount)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.cocoa.RetainCountBase + clang-analyzer-osx.cocoa + + true + Retain Count Base + + + + Major + + + + + + + false + false + clang-analyzer-osx.cocoa.RunLoopAutoreleaseLeak + clang-analyzer-osx.cocoa + + true + Run Loop Autorelease Leak + <p>Check for leaked memory in autorelease pools that will never be drained.</p> <p>(Clang-Tidy original name: clang-analyzer-osx.cocoa.RunLoopAutoreleaseLeak)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.cocoa.SuperDealloc + clang-analyzer-osx.cocoa + + true + Super Dealloc + <p>Warn about improper use of ‘<a href="#CT_SA_OSX_CCA_SD">super dealloc</a>’ in Objective-C.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="er">@</span>interface SuperDeallocThenReleaseIvarClass : NSObject { NSObject *_ivar; } <span class="er">@</span>end <span class="er">@</span>implementation SuperDeallocThenReleaseIvarClass - (<span class="dt">void</span>)dealloc { [super dealloc]; [_ivar release]; <span class="co">// warn</span> } <span class="er">@</span>end</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-osx.cocoa.SuperDealloc)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.cocoa.SelfInit + clang-analyzer-osx.cocoa + + true + Self Init + <p>Check that ‘self’ is properly initialized inside an initializer method.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="er">@</span>interface MyObj : NSObject { id x; } - (id)init; <span class="er">@</span>end <span class="er">@</span>implementation MyObj - (id)init { [super init]; x = <span class="dv">0</span>; <span class="co">// warn: instance variable used while &#39;self&#39; is not</span> <span class="co">// initialized</span> <span class="kw">return</span> <span class="dv">0</span>; } <span class="er">@</span>end <span class="er">@</span>interface MyObj : NSObject - (id)init; <span class="er">@</span>end <span class="er">@</span>implementation MyObj - (id)init { [super init]; <span class="kw">return</span> self; <span class="co">// warn: returning uninitialized &#39;self&#39;</span> } <span class="er">@</span>end</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-osx.cocoa.SelfInit)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.cocoa.UnusedIvars + clang-analyzer-osx.cocoa + + true + Unused Ivars + <p>Warn about private ivars that are never used.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="er">@</span>interface MyObj : NSObject { <span class="er">@</span>private id x; <span class="co">// warn</span> } <span class="er">@</span>end <span class="er">@</span>implementation MyObj <span class="er">@</span>end</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-osx.cocoa.UnusedIvars)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.cocoa.VariadicMethodTypes + clang-analyzer-osx.cocoa + + true + Variadic Method Types + <p>Check for passing non-Objective-C types to variadic collection initialization methods that expect only Objective-C types.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { [NSSet setWithObjects:<span class="er">@</span><span class="st">&quot;Foo&quot;</span>, <span class="st">&quot;Bar&quot;</span>, nil]; <span class="co">// warn: argument should be an ObjC pointer type, not &#39;char *&#39;</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-osx.cocoa.VariadicMethodTypes)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.coreFoundation.CFError + clang-analyzer-osx.coreFoundation + + true + CF Error + <p>Check usage of CFErrorRef* parameters</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test(CFErrorRef *error) { <span class="co">// warn: function accepting CFErrorRef* should have a</span> <span class="co">// non-void return</span> } <span class="dt">int</span> foo(CFErrorRef *error) { *error = <span class="dv">0</span>; <span class="co">// warn: potential null dereference</span> <span class="kw">return</span> <span class="dv">0</span>; }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-osx.coreFoundation.CFError)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.coreFoundation.CFNumber + clang-analyzer-osx.coreFoundation + + true + CF Number + <p>Check for proper uses of CFNumber APIs.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">CFNumberRef test(<span class="dt">unsigned</span> <span class="dt">char</span> x) { <span class="kw">return</span> CFNumberCreate(<span class="dv">0</span>, kCFNumberSInt16Type, &amp;x); <span class="co">// warn: 8 bit integer is used to initialize a 16 bit integer</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-osx.coreFoundation.CFNumber)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.coreFoundation.CFRetainRelease + clang-analyzer-osx.coreFoundation + + true + CF Retain Release + <p>Check for null arguments to CFRetain/CFRelease/CFMakeCollectable.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test(CFTypeRef p) { <span class="kw">if</span> (!p) CFRetain(p); <span class="co">// warn</span> } <span class="dt">void</span> test(<span class="dt">int</span> x, CFTypeRef p) { <span class="kw">if</span> (p) <span class="kw">return</span>; CFRelease(p); <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-osx.coreFoundation.CFRetainRelease)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.coreFoundation.containers.OutOfBounds + clang-analyzer-osx.coreFoundation.containers + + true + Out Of Bounds + <p>Checks for index out-of-bounds when using ‘CFArray’ API.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { CFArrayRef A = CFArrayCreate(<span class="dv">0</span>, <span class="dv">0</span>, <span class="dv">0</span>, &amp;kCFTypeArrayCallBacks); CFArrayGetValueAtIndex(A, <span class="dv">0</span>); <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-osx.coreFoundation.containers.OutOfBounds)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.coreFoundation.containers.PointerSizedValues + clang-analyzer-osx.coreFoundation.containers + + true + Pointer Sized Values + <p>Warns if ‘CFArray’, ‘CFDictionary’, ‘CFSet’ are created with non-pointer-size values.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { <span class="dt">int</span> x[] = { <span class="dv">1</span> }; CFArrayRef A = CFArrayCreate(<span class="dv">0</span>, (<span class="dt">const</span> <span class="dt">void</span> <span class="st">&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;</span>)x, <span class="dv">1</span>, &amp;kCFTypeArrayCallBacks); <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-osx.coreFoundation.containers.PointerSizedValues)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.MIG + clang-analyzer-osx + + true + Mach Interface Generator Calling Convention + + + + Major + + + + + + + false + false + clang-analyzer-osx.NumberObjectConversion + clang-analyzer-osx + + true + Number Object Conversion + <p>Check for erroneous conversions of objects representing numbers into numbers.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">NSNumber *photoCount = [albumDescriptor objectForKey:<span class="er">@</span><span class="st">&quot;PhotoCount&quot;</span>]; <span class="co">// Warning: Comparing a pointer value of type &#39;NSNumber *&#39;</span> <span class="co">// to a scalar integer value</span> <span class="kw">if</span> (photoCount &gt; <span class="dv">0</span>) { [self displayPhotos]; }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-osx.NumberObjectConversion)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.NSOrCFErrorDerefChecker + clang-analyzer-osx + + true + Ns Or CF Error Deref Checker + + + + Major + + + + + + + false + false + clang-analyzer-osx.ObjCProperty + clang-analyzer-osx + + true + Obj C Property + <p>Check for proper uses of Objective-C properties.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">NSNumber *photoCount = [albumDescriptor objectForKey:<span class="er">@</span><span class="st">&quot;PhotoCount&quot;</span>]; <span class="co">// Warning: Comparing a pointer value of type &#39;NSNumber *&#39;</span> <span class="co">// to a scalar integer value</span> <span class="kw">if</span> (photoCount &gt; <span class="dv">0</span>) { [self displayPhotos]; }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-osx.ObjCProperty)</p> + + + + Major + + + + + + + false + false + clang-analyzer-osx.OSObjectRetainCount + clang-analyzer-osx + + true + OSObject Retain Count + + + + Major + + + + + + + false + false + clang-analyzer-osx.SecKeychainAPI + clang-analyzer-osx + + true + Sec Keychain API + <p>Check for proper uses of Secure Keychain APIs.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { <span class="dt">unsigned</span> <span class="dt">int</span> *ptr = <span class="dv">0</span>; UInt32 length; SecKeychainItemFreeContent(ptr, &amp;length); <span class="co">// warn: trying to free data which has not been allocated</span> } <span class="dt">void</span> test() { <span class="dt">unsigned</span> <span class="dt">int</span> *ptr = <span class="dv">0</span>; UInt32 *length = <span class="dv">0</span>; <span class="dt">void</span> *outData; OSStatus st = SecKeychainItemCopyContent(<span class="dv">2</span>, ptr, ptr, length, outData); <span class="co">// warn: data is not released</span> } <span class="dt">void</span> test() { <span class="dt">unsigned</span> <span class="dt">int</span> *ptr = <span class="dv">0</span>; UInt32 *length = <span class="dv">0</span>; <span class="dt">void</span> *outData; OSStatus st = SecKeychainItemCopyContent(<span class="dv">2</span>, ptr, ptr, length, &amp;outData); SecKeychainItemFreeContent(ptr, outData); <span class="co">// warn: only call free if a non-NULL buffer was returned</span> } <span class="dt">void</span> test() { <span class="dt">unsigned</span> <span class="dt">int</span> *ptr = <span class="dv">0</span>; UInt32 *length = <span class="dv">0</span>; <span class="dt">void</span> *outData; OSStatus st = SecKeychainItemCopyContent(<span class="dv">2</span>, ptr, ptr, length, &amp;outData); st = SecKeychainItemCopyContent(<span class="dv">2</span>, ptr, ptr, length, &amp;outData); <span class="co">// warn: release data before another call to the allocator</span> <span class="kw">if</span> (st == noErr) SecKeychainItemFreeContent(ptr, outData); } <span class="dt">void</span> test() { SecKeychainItemRef itemRef = <span class="dv">0</span>; SecKeychainAttributeInfo *info = <span class="dv">0</span>; SecItemClass *itemClass = <span class="dv">0</span>; SecKeychainAttributeList *attrList = <span class="dv">0</span>; UInt32 *length = <span class="dv">0</span>; <span class="dt">void</span> *outData = <span class="dv">0</span>; OSStatus st = SecKeychainItemCopyAttributesAndData(itemRef, info, itemClass, &amp;attrList, length, &amp;outData); SecKeychainItemFreeContent(attrList, outData); <span class="co">// warn: deallocator doesn&#39;t match the allocator</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-osx.SecKeychainAPI)</p> + + + + Major + + + + + + + true + false + clang-analyzer-security.insecureAPI.bcmp + clang-analyzer-security.insecureAPI + + true + bcmp + <p>Warn on uses of the ‘bcmp’ function.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { bcmp(ptr0, ptr1, n); <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-security.insecureAPI.bcmp)</p> + + + + Major + + + + + + + true + false + clang-analyzer-security.insecureAPI.bcopy + clang-analyzer-security.insecureAPI + + true + bcopy + <p>Warn on uses of the ‘bcopy’ function.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { bcopy(src, dst, n); <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-security.insecureAPI.bcopy)</p> + + + + Major + + + + + + + true + false + clang-analyzer-security.insecureAPI.bzero + clang-analyzer-security.insecureAPI + + true + bzero + <p>Warn on uses of the ‘bzero’ function.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { bzero(ptr, n); <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-security.insecureAPI.bzero)</p> + + + + Major + + + + + + + true + false + clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling + clang-analyzer-security.insecureAPI + + true + Deprecated Or Unsafe Buffer Handling + <p>Warn on occurrences of unsafe or deprecated buffer handling functions, which now have a secure variant: sprintf, vsprintf, scanf, wscanf, fscanf, fwscanf, vscanf, vwscanf, vfscanf, vfwscanf, sscanf, swscanf, vsscanf, vswscanf, swprintf, snprintf, vswprintf, vsnprintf, memcpy, memmove, strncpy, strncat, memset</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { <span class="dt">char</span> buf [<span class="dv">5</span>]; strncpy(buf, <span class="st">&quot;a&quot;</span>, <span class="dv">1</span>); <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)</p> + + + + Major + + + + + + + true + false + clang-analyzer-security.insecureAPI.decodeValueOfObjCType + clang-analyzer-security.insecureAPI + + true + decode Value Of ObjC Type + + + + Major + + + + + + + true + false + clang-analyzer-security.FloatLoopCounter + clang-analyzer-security + + true + Float Loop Counter + <p>Warn on using a floating point value as a loop counter (CERT: FLP30-C, FLP30-CPP).</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { <span class="kw">for</span> (<span class="dt">float</span> x = <span class="fl">0.1f</span>; x &lt;= <span class="fl">1.0f</span>; x += <span class="fl">0.1f</span>) {} <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-security.FloatLoopCounter)</p> + + + + Major + + + + + + + true + false + clang-analyzer-security.insecureAPI.getpw + clang-analyzer-security.insecureAPI + + true + getpw + <p>Warn on uses of the ‘getpw’ function.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { <span class="dt">char</span> buff[<span class="dv">1024</span>]; getpw(<span class="dv">2</span>, buff); <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-security.insecureAPI.getpw)</p> + + + + Major + + + + + + + true + false + clang-analyzer-security.insecureAPI.gets + clang-analyzer-security.insecureAPI + + true + gets + <p>Warn on uses of the ‘gets’ function.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { <span class="dt">char</span> buff[<span class="dv">1024</span>]; gets(buff); <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-security.insecureAPI.gets)</p> + + + + Major + + + + + + + true + false + clang-analyzer-security.insecureAPI.mkstemp + clang-analyzer-security.insecureAPI + + true + mkstemp + <p>Warn when ‘mkstemp’ is passed fewer than 6 X’s in the format string.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { mkstemp(<span class="st">&quot;XX&quot;</span>); <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-security.insecureAPI.mkstemp)</p> + + + + Major + + + + + + + true + false + clang-analyzer-security.insecureAPI.mktemp + clang-analyzer-security.insecureAPI + + true + mktemp + <p>Warn on uses of the mktemp function.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { <span class="dt">char</span> *x = mktemp(<span class="st">&quot;/tmp/zxcv&quot;</span>); <span class="co">// warn: insecure, use mkstemp</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-security.insecureAPI.mktemp)</p> + + + + Major + + + + + + + true + false + clang-analyzer-security.insecureAPI.rand + clang-analyzer-security.insecureAPI + + true + rand + <p>Warn on uses of inferior random number generating functions (only if arc4random function is available): drand48, erand48, jrand48, lcong48, lrand48, mrand48, nrand48, random, rand_r.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { random(); <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-security.insecureAPI.rand)</p> + + + + Major + + + + + + + true + false + clang-analyzer-security.insecureAPI.strcpy + clang-analyzer-security.insecureAPI + + true + strcpy + <p>Warn on uses of the strcpy and strcat functions.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { <span class="dt">char</span> x[<span class="dv">4</span>]; <span class="dt">char</span> *y = <span class="st">&quot;abcd&quot;</span>; strcpy(x, y); <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-security.insecureAPI.strcpy)</p> + + + + Major + + + + + + + true + false + clang-analyzer-security.insecureAPI.SecuritySyntaxChecker + clang-analyzer-security.insecureAPI + + true + Security Syntax Checker + + + + Major + + + + + + + true + false + clang-analyzer-security.insecureAPI.UncheckedReturn + clang-analyzer-security.insecureAPI + + true + Unchecked Return + <p>Warn on uses of functions whose return values must be always checked.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { setuid(<span class="dv">1</span>); <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-security.insecureAPI.UncheckedReturn)</p> + + + + Major + + + + + + + true + false + clang-analyzer-security.insecureAPI.vfork + clang-analyzer-security.insecureAPI + + true + vfork + <p>Warn on uses of the ‘vfork’ function.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { vfork(); <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-security.insecureAPI.vfork)</p> + + + + Major + + + + + + + true + false + clang-analyzer-core.uninitialized.Assign + clang-analyzer-core.uninitialized + + true + Assign + <p>Check for assigning uninitialized values.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { <span class="dt">int</span> x; x |= <span class="dv">1</span>; <span class="co">// warn: left expression is uninitialized</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-core.uninitialized.Assign)</p> + + + + Major + + + + + + + true + false + clang-analyzer-core.uninitialized.ArraySubscript + clang-analyzer-core.uninitialized + + true + Array Subscript + <p>Check for uninitialized values used as array subscripts.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { <span class="dt">int</span> i, a[<span class="dv">10</span>]; <span class="dt">int</span> x = a[i]; <span class="co">// warn: array subscript is undefined</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-core.uninitialized.ArraySubscript)</p> + + + + Major + + + + + + + true + false + clang-analyzer-core.uninitialized.Branch + clang-analyzer-core.uninitialized + + true + Branch + <p>Check for uninitialized values used as branch conditions.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { <span class="dt">int</span> x; <span class="kw">if</span> (x) <span class="co">// warn</span> <span class="kw">return</span>; }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-core.uninitialized.Branch)</p> + + + + Major + + + + + + + true + false + clang-analyzer-core.uninitialized.CapturedBlockVariable + clang-analyzer-core.uninitialized + + true + Captured Block Variable + <p>Check for blocks that capture uninitialized values.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { <span class="dt">int</span> x; ^{ <span class="dt">int</span> y = x; }(); <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-core.uninitialized.CapturedBlockVariable)</p> + + + + Major + + + + + + + true + false + clang-analyzer-core.uninitialized.UndefReturn + clang-analyzer-core.uninitialized + + true + Undef Return + <p>Check for uninitialized values being returned to the caller.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> test() { <span class="dt">int</span> x; <span class="kw">return</span> x; <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-core.uninitialized.UndefReturn)</p> + + + + Major + + + + + + + true + false + clang-analyzer-unix.API + clang-analyzer-unix + + true + API + <p>Check calls to various UNIX/Posix functions: open, pthread_once, calloc, malloc, realloc, alloca.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"> <span class="co">// Currently the check is performed for apple targets only.</span> <span class="dt">void</span> test(<span class="dt">const</span> <span class="dt">char</span> *path) { <span class="dt">int</span> fd = open(path, O_CREAT); <span class="co">// warn: call to &#39;open&#39; requires a third argument when the</span> <span class="co">// &#39;O_CREAT&#39; flag is set</span> } <span class="dt">void</span> f(); <span class="dt">void</span> test() { pthread_once_t pred = {<span class="bn">0x30B1BCBA</span>, {<span class="dv">0</span>}}; pthread_once(&amp;pred, f); <span class="co">// warn: call to &#39;pthread_once&#39; uses the local variable</span> } <span class="dt">void</span> test() { <span class="dt">void</span> *p = malloc(<span class="dv">0</span>); <span class="co">// warn: allocation size of 0 bytes</span> } <span class="dt">void</span> test() { <span class="dt">void</span> *p = calloc(<span class="dv">0</span>, <span class="dv">42</span>); <span class="co">// warn: allocation size of 0 bytes</span> } <span class="dt">void</span> test() { <span class="dt">void</span> *p = malloc(<span class="dv">1</span>); p = realloc(p, <span class="dv">0</span>); <span class="co">// warn: allocation size of 0 bytes</span> } <span class="dt">void</span> test() { <span class="dt">void</span> *p = alloca(<span class="dv">0</span>); <span class="co">// warn: allocation size of 0 bytes</span> } <span class="dt">void</span> test() { <span class="dt">void</span> *p = valloc(<span class="dv">0</span>); <span class="co">// warn: allocation size of 0 bytes</span> } </code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-unix.API)</p> + + + + Major + + + + + + + true + false + clang-analyzer-unix.cstring.BadSizeArg + clang-analyzer-unix.cstring + + true + Bad Size Arg + <p>Check the size argument passed into C string functions for common erroneous patterns. Use -Wno-strncat-size compiler option to mute other strncat-related compiler warnings.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { <span class="dt">char</span> dest[<span class="dv">3</span>]; strncat(dest, <span class="st">&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;*&quot;</span>, <span class="kw">sizeof</span>(dest)); <span class="co">// warn: potential buffer overflow</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-unix.cstring.BadSizeArg)</p> + + + + Major + + + + + + + true + false + clang-analyzer-unix.Malloc + clang-analyzer-unix + + true + Malloc + <p>Check for memory leaks, double free, and use-after-free problems. Traces memory managed by malloc()/free().</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"> <span class="dt">void</span> test() { <span class="dt">int</span> *p = malloc(<span class="dv">1</span>); free(p); free(p); <span class="co">// warn: attempt to free released memory</span> } <span class="dt">void</span> test() { <span class="dt">int</span> *p = malloc(<span class="kw">sizeof</span>(<span class="dt">int</span>)); free(p); *p = <span class="dv">1</span>; <span class="co">// warn: use after free</span> } <span class="dt">void</span> test() { <span class="dt">int</span> *p = malloc(<span class="dv">1</span>); <span class="kw">if</span> (p) <span class="kw">return</span>; <span class="co">// warn: memory is never released</span> } <span class="dt">void</span> test() { <span class="dt">int</span> a[] = { <span class="dv">1</span> }; free(a); <span class="co">// warn: argument is not allocated by malloc</span> } <span class="dt">void</span> test() { <span class="dt">int</span> *p = malloc(<span class="kw">sizeof</span>(<span class="dt">char</span>)); p = p - <span class="dv">1</span>; free(p); <span class="co">// warn: argument to free() is offset by -4 bytes</span> } </code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-unix.Malloc)</p> + + + + Major + + + + + + + true + false + clang-analyzer-unix.MismatchedDeallocator + clang-analyzer-unix + + true + Mismatched Deallocator + <p>Check for mismatched deallocators.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="co">// C, C++</span> <span class="dt">void</span> test() { <span class="dt">int</span> *p = (<span class="dt">int</span> *)malloc(<span class="kw">sizeof</span>(<span class="dt">int</span>)); <span class="kw">delete</span> p; <span class="co">// warn</span> } <span class="co">// C, C++</span> <span class="dt">void</span> __attribute((ownership_returns(malloc))) *user_malloc(size_t); <span class="dt">void</span> test() { <span class="dt">int</span> *p = (<span class="dt">int</span> *)user_malloc(<span class="kw">sizeof</span>(<span class="dt">int</span>)); <span class="kw">delete</span> p; <span class="co">// warn</span> } <span class="co">// C, C++</span> <span class="dt">void</span> test() { <span class="dt">int</span> *p = <span class="kw">new</span> <span class="dt">int</span>; free(p); <span class="co">// warn</span> } <span class="co">// C, C++</span> <span class="dt">void</span> test() { <span class="dt">int</span> *p = <span class="kw">new</span> <span class="dt">int</span>[<span class="dv">1</span>]; realloc(p, <span class="kw">sizeof</span>(<span class="dt">long</span>)); <span class="co">// warn</span> } <span class="co">// C, C++</span> <span class="kw">template</span> &lt;<span class="kw">typename</span> T&gt; <span class="kw">struct</span> SimpleSmartPointer { T *ptr; <span class="kw">explicit</span> SimpleSmartPointer(T *p = <span class="dv">0</span>) : ptr(p) {} ~SimpleSmartPointer() { <span class="kw">delete</span> ptr; <span class="co">// warn</span> } }; <span class="dt">void</span> test() { SimpleSmartPointer&lt;<span class="dt">int</span>&gt; a((<span class="dt">int</span> *)malloc(<span class="dv">4</span>)); } <span class="co">// C++</span> <span class="dt">void</span> test() { <span class="dt">int</span> *p = (<span class="dt">int</span> *)<span class="kw">operator</span> <span class="kw">new</span>(<span class="dv">0</span>); <span class="kw">delete</span>[] p; <span class="co">// warn</span> } <span class="co">// Objective-C, C++</span> <span class="dt">void</span> test(NSUInteger dataLength) { <span class="dt">int</span> *p = <span class="kw">new</span> <span class="dt">int</span>; NSData *d = [NSData dataWithBytesNoCopy:p length:<span class="kw">sizeof</span>(<span class="dt">int</span>) freeWhenDone:<span class="dv">1</span>]; <span class="co">// warn +dataWithBytesNoCopy:length:freeWhenDone: cannot take</span> <span class="co">// ownership of memory allocated by &#39;new&#39;</span> } </code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-unix.MismatchedDeallocator)</p> + + + + Major + + + + + + + true + false + clang-analyzer-unix.MallocSizeof + clang-analyzer-unix + + true + Malloc Sizeof + <p>Check for dubious malloc arguments involving sizeof.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">void</span> test() { <span class="dt">long</span> *p = malloc(<span class="kw">sizeof</span>(<span class="dt">short</span>)); <span class="co">// warn: result is converted to &#39;long *&#39;, which is</span> <span class="co">// incompatible with operand type &#39;short&#39;</span> free(p); }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-unix.MallocSizeof)</p> + + + + Major + + + + + + + true + false + clang-analyzer-unix.cstring.NullArg + clang-analyzer-unix.cstring + + true + Null Arg + <p>Check for null pointers being passed as arguments to C string functions: strlen, strnlen, strcpy, strncpy, strcat, strncat, strcmp, strncmp, strcasecmp, strncasecmp.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> test() { <span class="kw">return</span> strlen(<span class="dv">0</span>); <span class="co">// warn</span> }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-unix.cstring.NullArg)</p> + + + + Major + + + + + + + true + false + clang-analyzer-unix.Vfork + clang-analyzer-unix + + true + Vfork + <p>Check for proper usage of vfork.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="dt">int</span> test(<span class="dt">int</span> x) { pid_t pid = vfork(); <span class="co">// warn</span> <span class="kw">if</span> (pid != <span class="dv">0</span>) <span class="kw">return</span> <span class="dv">0</span>; <span class="kw">switch</span> (x) { <span class="kw">case</span> <span class="dv">0</span>: pid = <span class="dv">1</span>; execl(<span class="st">&quot;&quot;</span>, <span class="st">&quot;&quot;</span>, <span class="dv">0</span>); _exit(<span class="dv">1</span>); <span class="kw">break</span>; <span class="kw">case</span> <span class="dv">1</span>: x = <span class="dv">0</span>; <span class="co">// warn: this assignment is prohibited</span> <span class="kw">break</span>; <span class="kw">case</span> <span class="dv">2</span>: foo(); <span class="co">// warn: this function call is prohibited</span> <span class="kw">break</span>; <span class="kw">default</span>: <span class="kw">return</span> <span class="dv">0</span>; <span class="co">// warn: return is prohibited</span> } <span class="kw">while</span>(<span class="dv">1</span>); }</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-unix.Vfork)</p> + + + + Major + + + + + + + true + false + clang-analyzer-valist.CopyToSelf + clang-analyzer-valist + + true + Copy To Self + + + + Major + + + + + + + true + false + clang-analyzer-valist.Uninitialized + clang-analyzer-valist + + true + Uninitialized + + + + Major + + + + + + + true + false + clang-analyzer-valist.Unterminated + clang-analyzer-valist + + true + Unterminated + + + + Major + + + + + + + true + false + clang-analyzer-valist.ValistBase + clang-analyzer-valist + + true + Valist Base + + + + Major + + + + + + + false + false + clang-analyzer-webkit.NoUncountedMemberChecker + clang-analyzer-webkit + + true + No Uncounted Member Checker + <p>Raw pointers and references to uncounted types can’t be used as class members. Only ref-counted types are allowed.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> RefCntbl { <span class="dt">void</span> ref() {} <span class="dt">void</span> deref() {} }; <span class="kw">struct</span> Foo { RefCntbl * ptr; <span class="co">// warn</span> RefCntbl &amp; ptr; <span class="co">// warn</span> <span class="co">// ...</span> };</code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-webkit.NoUncountedMemberChecker)</p> + + + + Major + + + + + + + false + false + clang-analyzer-webkit.RefCntblBaseVirtualDtor + clang-analyzer-webkit + + true + Ref Cntbl Base Virtual Dtor + <p>All uncounted types used as base classes must have a virtual destructor.</p> <p>Ref-counted types hold their ref-countable data by a raw pointer and allow implicit upcasting from ref-counted pointer to derived type to ref-counted pointer to base type. This might lead to an object of (dynamic) derived type being deleted via pointer to the base class type which C++ standard defines as UB in case the base class doesn’t have virtual destructor [expr.delete].</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">struct</span> RefCntblBase { <span class="dt">void</span> ref() {} <span class="dt">void</span> deref() {} }; <span class="kw">struct</span> Derived : RefCntblBase { }; <span class="co">// warn</span></code></pre></div> <p>(Clang-Tidy original name: clang-analyzer-webkit.RefCntblBaseVirtualDtor)</p> + + + + Major + + + + + + + false + false + clang-analyzer-webkit.UncountedLambdaCapturesChecker + clang-analyzer-webkit + + true + Uncounted Lambda Captures Checker + + + + Major + + + + + + + false + false + zircon-temporary-objects + zircon + + true + Temporary Objects + <p>Warns on construction of specific temporary objects in the Zircon kernel. If the object should be flagged, If the object should be flagged, the fully qualified type name must be explicitly passed to the check.</p> <p>For example, given the list of classes “Foo” and “NS::Bar”, all of the following will trigger the warning:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">Foo(); Foo F = Foo(); func(Foo()); <span class="kw">namespace</span> NS { Bar(); }</code></pre></div> <p>With the same list, the following will not trigger the warning:</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp">Foo F; <span class="co">// Non-temporary construction okay</span> Foo F(param); <span class="co">// Non-temporary construction okay</span> Foo *F = <span class="kw">new</span> Foo(); <span class="co">// New construction okay</span> Bar(); <span class="co">// Not NS::Bar, so okay</span> NS::Bar B; <span class="co">// Non-temporary construction okay</span></code></pre></div> <p>Note that objects must be explicitly specified in order to be flagged, and so objects that inherit a specified object will not be flagged.</p> <p>This check matches temporary objects without regard for inheritance and so a prohibited base class type does not similarly prohibit derived class types.</p> <div class="sourceCode"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">class</span> Derived : Foo {} <span class="co">// Derived is not explicitly disallowed</span> Derived(); <span class="co">// and so temporary construction is okay</span></code></pre></div> <h5 id="options-59">Options</h5> <p>Names</p> <p>A semi-colon-separated list of fully-qualified names of C++ classes that should not be constructed as temporaries. Default is empty.</p> <p>(Clang-Tidy original name: zircon-temporary-objects)</p> + + + + Major + + + + + + + true + true + summarized + + true + Abseil + Checks related to Abseil library. + + + + + + + + + true + true + summarized + + true + Altera + Checks related to OpenCL programming for FPGAs. + + + + + + + + + true + true + summarized + + true + Android + Checks related to Android. + + + + + + + + + true + true + summarized + + true + Boost + Checks related to Boost library. + + + + + + + + + true + true + summarized + + true + Bugprone + Checks that target bugprone code constructs. + + + + + + + + + true + true + summarized + + true + Cert + Checks related to CERT Secure Coding Guidelines. + + + + + + + + + true + true + summarized + + true + Static Analyzer - Core + General-purpose checkers. + + + + + + + + + true + true + summarized + + true + Static Analyzer - Core/Builtin + Checkers for builtin functions. + + + + + + + + + true + true + summarized + + true + Static Analyzer - Core/Uninitialized + Checkers for initalization issues. + + + + + + + + + true + true + summarized + + true + Static Analyzer - C++ + C++ checkers. + + + + + + + + + true + true + summarized + + true + Static Analyzer - Dead Code + Dead Code Checkers. + + + + + + + + + true + true + summarized + + true + Static Analyzer - Fuchsia + Checkers that can find various misuses of Fuchsia APIs. + + + + + + + + + true + true + summarized + + true + Static Analyzer - Nullability + Objective C checkers that warn for null pointer passing and dereferencing errors. + + + + + + + + + true + true + summarized + + true + Static Analyzer - OptIn/C++ + Opt In C++ checkers. + + + + + + + + + true + true + summarized + + true + Static Analyzer - OptIn/MPI + Opt In MPI checkers. + + + + + + + + + true + true + summarized + + true + Static Analyzer - OptIn/macOS + Opt In macOS checkers. + + + + + + + + + true + true + summarized + + true + Static Analyzer - OptIn/Cocoa Localizability + Opt In macOS Cocoa localizability checkers. + + + + + + + + + true + true + summarized + + true + Static Analyzer - OptIn/Performance + Opt In performance checkers. + + + + + + + + + true + true + summarized + + true + Static Analyzer - OptIn/Portability + Opt In portability checkers. + + + + + + + + + true + true + summarized + + true + Static Analyzer - macOS + macOS checkers. + + + + + + + + + true + true + summarized + + true + Static Analyzer - macOS/Cocoa API + macOS Cocoa API checkers + + + + + + + + + true + true + summarized + + true + Static Analyzer - macOS/Core Foundation + macOS Core Foundation checkers. + + + + + + + + + true + true + summarized + + true + Static Analyzer - macOS/Core Foundation/Containers + macOS Core Foundation container checkers. + + + + + + + + + true + true + summarized + + true + Static Analyzer - Security + Security related checkers. + + + + + + + + + true + true + summarized + + true + Static Analyzer - Security/Insecure API + Security related issues caused by inadequate API usage. + + + + + + + + + true + true + summarized + + true + Static Analyzer - Unix + POSIX/Unix checkers. + + + + + + + + + true + true + summarized + + true + Static Analyzer - Unix/C string + Checkers related to the C string. + + + + + + + + + true + true + summarized + + true + Static Analyzer - va_list + Checkers related to the usage of the va_list + + + + + + + + + true + true + summarized + + true + Static Analyzer - Webkit + Checkers that can find issues in WebKit codebase. + + + + + + + + + true + true + summarized + + true + Concurrency + Checks related to concurrent programming (including threads, fibers, coroutines, etc.). + + + + + + + + + true + true + summarized + + true + C++ Core Guidelines + Checks related to C++ Core Guidelines. + + + + + + + + + true + true + summarized + + true + Darwin + Checks related to Darwin coding conventions. + + + + + + + + + true + true + summarized + + true + Fuchsia + Checks related to Fuchsia coding conventions. + + + + + + + + + true + true + summarized + + true + Google + Checks related to Google coding conventions. + + + + + + + + + true + true + summarized + + true + High Integrity C++ + Checks related to High Integrity C++ Coding Standard. + + + + + + + + + true + true + summarized + + true + Linux Kernel + Checks related to the Linux Kernel coding conventions. + + + + + + + + + true + true + summarized + + true + LLVM + Checks related to the LLVM coding conventions. + + + + + + + + + true + true + summarized + + true + LLVM-libc + Checks related to the LLVM-libc coding standards. + + + + + + + + + true + true + summarized + + true + Miscellaneous + Checks that we didn’t have a better category for. + + + + + + + + + true + true + summarized + + true + Modernize + Checks that advocate usage of modern (currently “modern” means “C++11”) language constructs. + + + + + + + + + true + true + summarized + + true + MPI + Checks related to MPI (Message Passing Interface). + + + + + + + + + true + true + summarized + + true + Objective-C + Checks related to Objective-C coding conventions. + + + + + + + + + true + true + summarized + + true + OpenMP + Checks related to OpenMP API. + + + + + + + + + true + true + summarized + + true + Performance + Checks that target performance-related issues. + + + + + + + + + true + true + summarized + + true + Portability + Checks that target portability-related issues that don’t relate to any particular coding style. + + + + + + + + + true + true + summarized + + true + Readability + Checks that target readability-related issues that don’t relate to any particular coding style + + + + + + + + + true + true + summarized + + true + Zircon + Checks related to Zircon kernel coding conventions + + + + + + + diff --git a/cl/ClangTidy2Graph/inc/ResultConverter.h b/cl/ClangTidy2Graph/inc/ResultConverter.h new file mode 100644 index 0000000..64b0863 --- /dev/null +++ b/cl/ClangTidy2Graph/inc/ResultConverter.h @@ -0,0 +1,170 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _CLANGTIDY2GRAPH_RESULTCONVERTER_H_ +#define _CLANGTIDY2GRAPH_RESULTCONVERTER_H_ + +#include +#include +#include +#include +#include +#include + +using namespace columbus::io; + +namespace columbus { namespace clangtidy2graph{ + + + struct Note{ + std::string file; + int line; + int column; + std::string message; + }; + + /** + * \brief Structure for a warning. + */ + struct Warning{ + std::string file; + int line; + int column; + std::string message; + std::string name; + + std::list notes; + }; + + + //Handler for xml parser + class Handler : public SimpleXmlIO::XmlHandler{ + public: + ~Handler(); + /** + * \brief call, when read a xml begin tag + * \param name [in] the tag name + * \param list [in] the tag attruibutes + */ + void beginTag(const std::string& name, const AttributeList& list); + + /** + * \brief call, when read a xml content + * \param content [in] the content text + */ + void content(const std::string& content); + + /** + * \brief call, when read a xml end tag + * \param name [in] the tag name + */ + void endTag(const std::string& name); + + /** + * \brief Returns list of warnings + */ + std::list getWarnings(); + + /** + * \brief Clear list of warnings + */ + void clearWarnings(); + + private: + bool hasToSkip; //if the location is invalid, then skip whole diagnostic part + std::string currentTag; + bool isNote = false; + + // List of warnings + std::list warnings; + + /** + * \brief Resolve escape characters. + * \param content string. + */ + std::string resolveEscapeChars(std::string content); + }; + + class ResultConverter{ + + public: + + /** + * \brief Constructor + * + * \param limFileName The name of the lim file. + * \param txtOutFile The name of the plain text output file. + * \param rulFileName The name of the rul file. + * \param rulConfig Name of the rul config. + * \param exportRul Build the ruls into the graph. + */ + ResultConverter(const std::string& limFileName, const std::string& txtOutFile, const std::string& rulFileName, const std::string& rulConfig, const bool exportRul, const std::string& changePathFrom, const std::string& changePathTo); + + virtual ~ResultConverter(); + + /** + * \brief Process an output file of clang-tidy + * + * \param resultFileName The name of the file. + */ + void process(const std::string& resultFileName); + + + /** + * \brief Save the result graph into file. + * + * \param graphOutputFilename The name of the output file. + * \param createXMLdump Create xml dump. + */ + void saveResultGraph(const std::string& graphOutputFilename, bool createXMLdump); + + /** + * \brief Aggregate warnings. + */ + void aggregateWarnings(); + + private: + Handler handler; + + rul::RulHandler rulHandler; + RefDistributorStrTable limStrTable; + lim::asg::Factory limFactory; + graph::Graph graph; + graphsupport::GraphRangeIndexer& graphIndexer; + + const std::string& changePathFrom; + const std::string& changePathTo; + std::string txtOutFile; + graphsupport::WarningCache warningCache; + + int num_notes = 0, unable_to_add = 0, not_found = 0, success = 0, num_of_warnings = 0, not_defined = 0, invalid_node = 0, already_added = 0; //DEBUG + + /** + * \brief Add a warning into the graph. + */ + void addWarning(Warning& warning); + + }; + + +}} //namespace end: columbus, clangtidy2graph + + +#endif diff --git a/cl/ClangTidy2Graph/inc/defines.h b/cl/ClangTidy2Graph/inc/defines.h new file mode 100644 index 0000000..4fc86cd --- /dev/null +++ b/cl/ClangTidy2Graph/inc/defines.h @@ -0,0 +1,89 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _CLANGTIDY2GRAPH_DEFINES_H_ +#define _CLANGTIDY2GRAPH_DEFINES_H_ + +#include + +// xml version +#define _RESULT "results" +#define _RESULT_VERSION "version" + +// Rule +#define _RULE "error" +#define _RULE_ID "id" +#define _RULE_PRIORITY "severity" +#define _RULE_WARNING "msg" +#define _RULE_HELP "verbose" +#define _RULE_INCONCLUSIVE "inconclusive" + +// RuleName +#define _RULENAME "rule" + +// Group +#define _GROUPS "groups" +#define _GROUP "group" +#define _GROUP_ID "id" +#define _GROUP_NAME "name" +#define _GROUP_DESCRIPTION "description" +#define _GROUP_HELP "help" +#define _GROUP_RULE "error" +#define _GROUP_RULE_ID "id" + +// Warning +#define _DIAGNOSTIC "Diagnostic" +#define _DIAGNOSTIC_NAME "DiagnosticName" +#define _DIAGNOSTIC_MSG "Message" +#define _DIAGNOSTIC_LOCATION_FILE "FilePath" +#define _DIAGNOSTIC_LOCATION_LINE "Line" +#define _DIAGNOSTIC_LOCATION_COLUMN "Column" +#define _DIAGNOSTIC_NOTE "Notes" + +#define _RULE_PREFIX "CLANGTIDY_" + + +inline std::string formatDisplayName(const std::string& name){ + + std::ostringstream displaynameS; + + for(std::string::size_type i=0; i < name.length(); ++i){ + if(isupper(name[i]) && i > 0){ + displaynameS << " "; + } + displaynameS << name[i]; + } + + std::string ret = displaynameS.str(); + + ret[0] = toupper(ret[0]); + /* + if(ret.find("Obsolete Functions") != std::string::npos){ + ret = ret.substr(0, 18) + " " + ret.substr(18); + }else if(ret.find("Nonreentrant Functions") != std::string::npos){ + ret = ret.substr(0, 22) + " " + ret.substr(22); + }else if(ret == "Wrongmathcall"){ + ret = "Wrong Math Call"; + }*/ + + return ret; +} + +#endif diff --git a/cl/ClangTidy2Graph/inc/messages.h b/cl/ClangTidy2Graph/inc/messages.h new file mode 100644 index 0000000..afa08bd --- /dev/null +++ b/cl/ClangTidy2Graph/inc/messages.h @@ -0,0 +1,34 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _CLANGTIDY2GRAPH_MESSAGE_H_ +#define _CLANGTIDY2GRAPH_MESSAGE_H_ + +#define CMSG_NO_INPUT_FILE WriteMsg::mlError, "\nNo input file was given!\n\n" +#define CMSG_NO_OUTPUT_FILE WriteMsg::mlError, "\nNo output file was given!\n\n" +#define CMSG_FAILED_TO_OPEN_FILE WriteMsg::mlError, "File %s can't be opened!\n" +#define CMSG_UNABLE_TO_ADD_WARNING_AT_LOCATION WriteMsg::mlWarning, "Unable to add warning at location: %s(%d)\n" +#define CMSG_WRONG_XML_FORMAT_VERSION WriteMsg::mlWarning, "The given error list XML file has wrong format version number!\n" +#define CMSG_ORIGINAL_RULE_NOT_EXIST WriteMsg::mlWarning, "Original rule is not exists: %s\n" +#define CMSG_RULE_NOT_DEFINED WriteMsg::mlWarning, "Rule is not defined: %s\n" +#define CMSG_RULE_NO_NAME WriteMsg::mlWarning, "Rule %s does not have name!\n" +#define CMSG_FILE_NOT_EXISTS + +#endif diff --git a/cl/ClangTidy2Graph/rules.csv b/cl/ClangTidy2Graph/rules.csv new file mode 100644 index 0000000..bd8a422 --- /dev/null +++ b/cl/ClangTidy2Graph/rules.csv @@ -0,0 +1,419 @@ +FullName;Group;OldName;NewName;ID;Priority +abseil-duration-addition;abseil;duration-addition;Duration Addition;CT_DA;Major +abseil-duration-comparison;abseil;duration-comparison;Duration Comparison;CT_DC;Major +abseil-duration-conversion-cast;abseil;duration-conversion-cast;Duration Conversion Cast;CT_DCC;Major +abseil-duration-division;abseil;duration-division;Duration Division;CT_DD;Major +abseil-duration-factory-float;abseil;duration-factory-float;Duration Factory Float;CT_DFF;Major +abseil-duration-factory-scale;abseil;duration-factory-scale;Duration Factory Scale;CT_DFS;Major +abseil-duration-subtraction;abseil;duration-subtraction;Duration Subtraction;CT_DS;Major +abseil-duration-unnecessary-conversion;abseil;duration-unnecessary-conversion;Duration Unnecessary Conversion;CT_DUC;Major +abseil-faster-strsplit-delimiter;abseil;faster-strsplit-delimiter;Faster Strsplit Delimiter;CT_FSD;Major +abseil-no-internal-dependencies;abseil;no-internal-dependencies;No Internal Dependencies;CT_NID;Major +abseil-no-namespace;abseil;no-namespace;No Namespace;CT_NN;Major +abseil-redundant-strcat-calls;abseil;redundant-strcat-calls;Redundant Strcat Calls;CT_RSC;Major +abseil-str-cat-append;abseil;str-cat-append;Str Cat Append;CT_SCA;Major +abseil-string-find-startswith;abseil;string-find-startswith;String Find Startswith;CT_SFS;Major +abseil-string-find-str-contains;abseil;string-find-str-contains;String Find Str Contains;CT_SFSC;Major +abseil-time-comparison;abseil;time-comparison;Time Comparison;CT_TC;Major +abseil-time-subtraction;abseil;time-subtraction;Time Subtraction;CT_TS;Major +abseil-upgrade-duration-conversions;abseil;upgrade-duration-conversions;Upgrade Duration Conversions;CT_UDC;Major +altera-kernel-name-restriction;altera;kernel-name-restriction;Kernel Name Restriction;CT_KNR;Major +altera-single-work-item-barrier;altera;single-work-item-barrier;Single Work Item Barrier;CT_SWIB;Major +altera-struct-pack-align;altera;struct-pack-align;Struct Pack Align;CT_SPA;Major +android-cloexec-accept;android;cloexec-accept;Cloexec Accept;CT_CA;Major +android-cloexec-accept4;android;cloexec-accept4;Cloexec Accept4;CT_CA_2;Major +android-cloexec-creat;android;cloexec-creat;Cloexec Creat;CT_CC;Major +android-cloexec-dup;android;cloexec-dup;Cloexec Dup;CT_CD;Major +android-cloexec-epoll-create;android;cloexec-epoll-create;Cloexec Epoll Create;CT_CEC;Major +android-cloexec-epoll-create1;android;cloexec-epoll-create1;Cloexec Epoll Create1;CT_CEC_2;Major +android-cloexec-fopen;android;cloexec-fopen;Cloexec Fopen;CT_CF;Major +android-cloexec-inotify-init;android;cloexec-inotify-init;Cloexec Inotify Init;CT_CII;Major +android-cloexec-inotify-init1;android;cloexec-inotify-init1;Cloexec Inotify Init1;CT_CII_2;Major +android-cloexec-memfd-create;android;cloexec-memfd-create;Cloexec Memfd Create;CT_CMC;Major +android-cloexec-open;android;cloexec-open;Cloexec Open;CT_CO;Major +android-cloexec-pipe;android;cloexec-pipe;Cloexec Pipe;CT_CP;Major +android-cloexec-pipe2;android;cloexec-pipe2;Cloexec Pipe2;CT_CP_2;Major +android-cloexec-socket;android;cloexec-socket;Cloexec Socket;CT_CS;Major +android-comparison-in-temp-failure-retry;android;comparison-in-temp-failure-retry;Comparison In Temp Failure Retry;CT_CITFR;Major +boost-use-to-string;boost;use-to-string;Use To String;CT_UTS;Major +bugprone-argument-comment;bugprone;argument-comment;Argument Comment;CT_AC;Major +bugprone-assert-side-effect;bugprone;assert-side-effect;Assert Side Effect;CT_ASE;Major +bugprone-bad-signal-to-kill-thread;bugprone;bad-signal-to-kill-thread;Bad Signal To Kill Thread;CT_BSTKT;Major +bugprone-bool-pointer-implicit-conversion;bugprone;bool-pointer-implicit-conversion;Bool Pointer Implicit Conversion;CT_BPIC;Major +bugprone-branch-clone;bugprone;branch-clone;Branch Clone;CT_BC;Major +bugprone-copy-constructor-init;bugprone;copy-constructor-init;Copy Constructor Init;CT_CCI;Major +bugprone-dangling-handle;bugprone;dangling-handle;Dangling Handle;CT_DH;Major +bugprone-dynamic-static-initializers;bugprone;dynamic-static-initializers;Dynamic Static Initializers;CT_DSI;Major +bugprone-exception-escape;bugprone;exception-escape;Exception Escape;CT_EE;Major +bugprone-fold-init-type;bugprone;fold-init-type;Fold Init Type;CT_FIT;Major +bugprone-forward-declaration-namespace;bugprone;forward-declaration-namespace;Forward Declaration Namespace;CT_FDN;Major +bugprone-forwarding-reference-overload;bugprone;forwarding-reference-overload;Forwarding Reference Overload;CT_FRO;Major +bugprone-inaccurate-erase;bugprone;inaccurate-erase;Inaccurate Erase;CT_IE;Major +bugprone-incorrect-roundings;bugprone;incorrect-roundings;Incorrect Roundings;CT_IR;Major +bugprone-infinite-loop;bugprone;infinite-loop;Infinite Loop;CT_IL;Major +bugprone-integer-division;bugprone;integer-division;Integer Division;CT_ID;Major +bugprone-lambda-function-name;bugprone;lambda-function-name;Lambda Function Name;CT_LFN;Major +bugprone-macro-parentheses;bugprone;macro-parentheses;Macro Parentheses;CT_MP;Major +bugprone-macro-repeated-side-effects;bugprone;macro-repeated-side-effects;Macro Repeated Side Effects;CT_MRSE;Major +bugprone-misplaced-operator-in-strlen-in-alloc;bugprone;misplaced-operator-in-strlen-in-alloc;Misplaced Operator In Strlen In Alloc;CT_MOISIA;Major +bugprone-misplaced-pointer-arithmetic-in-alloc;bugprone;misplaced-pointer-arithmetic-in-alloc;Misplaced Pointer Arithmetic In Alloc;CT_MPAIA;Major +bugprone-misplaced-widening-cast;bugprone;misplaced-widening-cast;Misplaced Widening Cast;CT_MWC;Major +bugprone-move-forwarding-reference;bugprone;move-forwarding-reference;Move Forwarding Reference;CT_MFR;Major +bugprone-multiple-statement-macro;bugprone;multiple-statement-macro;Multiple Statement Macro;CT_MSM;Major +bugprone-no-escape;bugprone;no-escape;No Escape;CT_NE;Major +bugprone-not-null-terminated-result;bugprone;not-null-terminated-result;Not Null Terminated Result;CT_NNTR;Major +bugprone-parent-virtual-call;bugprone;parent-virtual-call;Parent Virtual Call;CT_PVC;Major +bugprone-posix-return;bugprone;posix-return;Posix Return;CT_PR;Major +bugprone-redundant-branch-condition;bugprone;redundant-branch-condition;Redundant Branch Condition;CT_RBC;Major +bugprone-reserved-identifier;bugprone;reserved-identifier;Reserved Identifier;CT_RI;Major +bugprone-signal-handler;bugprone;signal-handler;Signal Handler;CT_SH;Major +bugprone-signed-char-misuse;bugprone;signed-char-misuse;Signed Char Misuse;CT_SCM;Major +bugprone-sizeof-container;bugprone;sizeof-container;Sizeof Container;CT_SC;Major +bugprone-sizeof-expression;bugprone;sizeof-expression;Sizeof Expression;CT_SE;Major +bugprone-spuriously-wake-up-functions;bugprone;spuriously-wake-up-functions;Spuriously Wake Up Functions;CT_SWUF;Major +bugprone-string-constructor;bugprone;string-constructor;String Constructor;CT_SC_2;Major +bugprone-string-integer-assignment;bugprone;string-integer-assignment;String Integer Assignment;CT_SIA;Major +bugprone-string-literal-with-embedded-nul;bugprone;string-literal-with-embedded-nul;String Literal With Embedded Nul;CT_SLWEN;Major +bugprone-suspicious-enum-usage;bugprone;suspicious-enum-usage;Suspicious Enum Usage;CT_SEU;Major +bugprone-suspicious-include;bugprone;suspicious-include;Suspicious Include;CT_SI;Major +bugprone-suspicious-memset-usage;bugprone;suspicious-memset-usage;Suspicious Memset Usage;CT_SMU;Major +bugprone-suspicious-missing-comma;bugprone;suspicious-missing-comma;Suspicious Missing Comma;CT_SMC;Major +bugprone-suspicious-semicolon;bugprone;suspicious-semicolon;Suspicious Semicolon;CT_SS;Major +bugprone-suspicious-string-compare;bugprone;suspicious-string-compare;Suspicious String Compare;CT_SSC;Major +bugprone-swapped-arguments;bugprone;swapped-arguments;Swapped Arguments;CT_SA;Major +bugprone-terminating-continue;bugprone;terminating-continue;Terminating Continue;CT_TC_2;Major +bugprone-throw-keyword-missing;bugprone;throw-keyword-missing;Throw Keyword Missing;CT_TKM;Major +bugprone-too-small-loop-variable;bugprone;too-small-loop-variable;Too Small Loop Variable;CT_TSLV;Major +bugprone-undefined-memory-manipulation;bugprone;undefined-memory-manipulation;Undefined Memory Manipulation;CT_UMM;Major +bugprone-undelegated-constructor;bugprone;undelegated-constructor;Undelegated Constructor;CT_UC;Major +bugprone-unhandled-self-assignment;bugprone;unhandled-self-assignment;Unhandled Self Assignment;CT_USA;Major +bugprone-unused-raii;bugprone;unused-raii;Unused Raii;CT_UR;Major +bugprone-unused-return-value;bugprone;unused-return-value;Unused Return Value;CT_URV;Major +bugprone-use-after-move;bugprone;use-after-move;Use After Move;CT_UAM;Major +bugprone-virtual-near-miss;bugprone;virtual-near-miss;Virtual Near Miss;CT_VNM;Major +cert-con36-c;cert;con36-c;Con36 C;CT_CC_2;Major +cert-con54-cpp;cert;con54-cpp;Con54 Cpp;CT_CC_3;Major +cert-dcl03-c;cert;dcl03-c;Dcl03 C;CT_DC_2;Major +cert-dcl16-c;cert;dcl16-c;Dcl16 C;CT_DC_3;Major +cert-dcl21-cpp;cert;dcl21-cpp;Dcl21 Cpp;CT_DC_4;Major +cert-dcl37-c;cert;dcl37-c;Dcl37 C;CT_DC_5;Major +cert-dcl50-cpp;cert;dcl50-cpp;Dcl50 Cpp;CT_DC_6;Major +cert-dcl51-cpp;cert;dcl51-cpp;Dcl51 Cpp;CT_DC_7;Major +cert-dcl54-cpp;cert;dcl54-cpp;Dcl54 Cpp;CT_DC_8;Major +cert-dcl58-cpp;cert;dcl58-cpp;Dcl58 Cpp;CT_DC_9;Major +cert-dcl59-cpp;cert;dcl59-cpp;Dcl59 Cpp;CT_DC_10;Major +cert-env33-c;cert;env33-c;Env33 C;CT_EC;Major +cert-err09-cpp;cert;err09-cpp;Err09 Cpp;CT_EC_2;Major +cert-err34-c;cert;err34-c;Err34 C;CT_EC_3;Major +cert-err52-cpp;cert;err52-cpp;Err52 Cpp;CT_EC_4;Major +cert-err58-cpp;cert;err58-cpp;Err58 Cpp;CT_EC_5;Major +cert-err60-cpp;cert;err60-cpp;Err60 Cpp;CT_EC_6;Major +cert-err61-cpp;cert;err61-cpp;Err61 Cpp;CT_EC_7;Major +cert-fio38-c;cert;fio38-c;Fio38 C;CT_FC;Major +cert-flp30-c;cert;flp30-c;Flp30 C;CT_FC_2;Major +cert-mem57-cpp;cert;mem57-cpp;Mem57 Cpp;CT_MC;Major +cert-msc30-c;cert;msc30-c;Msc30 C;CT_MC_2;Major +cert-msc32-c;cert;msc32-c;Msc32 C;CT_MC_3;Major +cert-msc50-cpp;cert;msc50-cpp;Msc50 Cpp;CT_MC_4;Major +cert-msc51-cpp;cert;msc51-cpp;Msc51 Cpp;CT_MC_5;Major +cert-oop11-cpp;cert;oop11-cpp;Oop11 Cpp;CT_OC;Major +cert-oop54-cpp;cert;oop54-cpp;Oop54 Cpp;CT_OC_2;Major +cert-oop57-cpp;cert;oop57-cpp;Oop57 Cpp;CT_OC_3;Major +cert-oop58-cpp;cert;oop58-cpp;Oop58 Cpp;CT_OC_4;Major +cert-pos44-c;cert;pos44-c;Pos44 C;CT_PC;Major +cert-sig30-c;cert;sig30-c;Sig30 C;CT_SC_3;Major +cert-str34-c;cert;str34-c;Str34 C;CT_SC_4;Major +concurrency-mt-unsafe;concurrency;mt-unsafe;Mt Unsafe;CT_MU;Major +cppcoreguidelines-avoid-c-arrays;cppcoreguidelines;avoid-c-arrays;Avoid C Arrays;CT_ACA;Major +cppcoreguidelines-avoid-goto;cppcoreguidelines;avoid-goto;Avoid Goto;CT_AG;Major +cppcoreguidelines-avoid-magic-numbers;cppcoreguidelines;avoid-magic-numbers;Avoid Magic Numbers;CT_AMN;Major +cppcoreguidelines-avoid-non-const-global-variables;cppcoreguidelines;avoid-non-const-global-variables;Avoid Non Const Global Variables;CT_ANCGV;Major +cppcoreguidelines-c-copy-assignment-signature;cppcoreguidelines;c-copy-assignment-signature;C Copy Assignment Signature;CT_CCAS;Major +cppcoreguidelines-explicit-virtual-functions;cppcoreguidelines;explicit-virtual-functions;Explicit Virtual Functions;CT_EVF;Major +cppcoreguidelines-init-variables;cppcoreguidelines;init-variables;Init Variables;CT_IV;Major +cppcoreguidelines-interfaces-global-init;cppcoreguidelines;interfaces-global-init;Interfaces Global Init;CT_IGI;Major +cppcoreguidelines-macro-usage;cppcoreguidelines;macro-usage;Macro Usage;CT_MU_2;Major +cppcoreguidelines-narrowing-conversions;cppcoreguidelines;narrowing-conversions;Narrowing Conversions;CT_NC;Major +cppcoreguidelines-no-malloc;cppcoreguidelines;no-malloc;No Malloc;CT_NM;Major +cppcoreguidelines-non-private-member-variables-in-classes;cppcoreguidelines;non-private-member-variables-in-classes;Non Private Member Variables In Classes;CT_NPMVIC;Major +cppcoreguidelines-owning-memory;cppcoreguidelines;owning-memory;Owning Memory;CT_OM;Major +cppcoreguidelines-pro-bounds-array-to-pointer-decay;cppcoreguidelines;pro-bounds-array-to-pointer-decay;Pro Bounds Array To Pointer Decay;CT_PBATPD;Major +cppcoreguidelines-pro-bounds-constant-array-index;cppcoreguidelines;pro-bounds-constant-array-index;Pro Bounds Constant Array Index;CT_PBCAI;Major +cppcoreguidelines-pro-bounds-pointer-arithmetic;cppcoreguidelines;pro-bounds-pointer-arithmetic;Pro Bounds Pointer Arithmetic;CT_PBPA;Major +cppcoreguidelines-pro-type-const-cast;cppcoreguidelines;pro-type-const-cast;Pro Type Const Cast;CT_PTCC;Major +cppcoreguidelines-pro-type-cstyle-cast;cppcoreguidelines;pro-type-cstyle-cast;Pro Type Cstyle Cast;CT_PTCC_2;Major +cppcoreguidelines-pro-type-member-init;cppcoreguidelines;pro-type-member-init;Pro Type Member Init;CT_PTMI;Major +cppcoreguidelines-pro-type-reinterpret-cast;cppcoreguidelines;pro-type-reinterpret-cast;Pro Type Reinterpret Cast;CT_PTRC;Major +cppcoreguidelines-pro-type-static-cast-downcast;cppcoreguidelines;pro-type-static-cast-downcast;Pro Type Static Cast Downcast;CT_PTSCD;Major +cppcoreguidelines-pro-type-union-access;cppcoreguidelines;pro-type-union-access;Pro Type Union Access;CT_PTUA;Major +cppcoreguidelines-pro-type-vararg;cppcoreguidelines;pro-type-vararg;Pro Type Vararg;CT_PTV;Major +cppcoreguidelines-slicing;cppcoreguidelines;slicing;Slicing;CT_S;Major +cppcoreguidelines-special-member-functions;cppcoreguidelines;special-member-functions;Special Member Functions;CT_SMF;Major +darwin-avoid-spinlock;darwin;avoid-spinlock;Avoid Spinlock;CT_AS;Major +darwin-dispatch-once-nonstatic;darwin;dispatch-once-nonstatic;Dispatch Once Nonstatic;CT_DON;Major +fuchsia-default-arguments-calls;fuchsia;default-arguments-calls;Default Arguments Calls;CT_DAC;Major +fuchsia-default-arguments-declarations;fuchsia;default-arguments-declarations;Default Arguments Declarations;CT_DAD;Major +fuchsia-header-anon-namespaces;fuchsia;header-anon-namespaces;Header Anon Namespaces;CT_HAN;Major +fuchsia-multiple-inheritance;fuchsia;multiple-inheritance;Multiple Inheritance;CT_MI;Major +fuchsia-overloaded-operator;fuchsia;overloaded-operator;Overloaded Operator;CT_OO;Major +fuchsia-statically-constructed-objects;fuchsia;statically-constructed-objects;Statically Constructed Objects;CT_SCO;Major +fuchsia-trailing-return;fuchsia;trailing-return;Trailing Return;CT_TR;Major +fuchsia-virtual-inheritance;fuchsia;virtual-inheritance;Virtual Inheritance;CT_VI;Major +google-build-explicit-make-pair;google;build-explicit-make-pair;Build Explicit Make Pair;CT_BEMP;Major +google-build-namespaces;google;build-namespaces;Build Namespaces;CT_BN;Major +google-build-using-namespace;google;build-using-namespace;Build Using Namespace;CT_BUN;Major +google-default-arguments;google;default-arguments;Default Arguments;CT_DA_2;Major +google-explicit-constructor;google;explicit-constructor;Explicit Constructor;CT_EC_8;Major +google-global-names-in-headers;google;global-names-in-headers;Global Names In Headers;CT_GNIH;Major +google-objc-avoid-nsobject-new;google;objc-avoid-nsobject-new;Objc Avoid Nsobject New;CT_OANN;Major +google-objc-avoid-throwing-exception;google;objc-avoid-throwing-exception;Objc Avoid Throwing Exception;CT_OATE;Major +google-objc-function-naming;google;objc-function-naming;Objc Function Naming;CT_OFN;Major +google-objc-global-variable-declaration;google;objc-global-variable-declaration;Objc Global Variable Declaration;CT_OGVD;Major +google-readability-avoid-underscore-in-googletest-name;google;readability-avoid-underscore-in-googletest-name;Readability Avoid Underscore In Googletest Name;CT_RAUIGN;Major +google-readability-braces-around-statements;google;readability-braces-around-statements;Readability Braces Around Statements;CT_RBAS;Major +google-readability-casting;google;readability-casting;Readability Casting;CT_RC;Major +google-readability-function-size;google;readability-function-size;Readability Function Size;CT_RFS;Major +google-readability-namespace-comments;google;readability-namespace-comments;Readability Namespace Comments;CT_RNC;Major +google-readability-todo;google;readability-todo;Readability Todo;CT_RT;Major +google-runtime-int;google;runtime-int;Runtime Int;CT_RI_2;Major +google-runtime-operator;google;runtime-operator;Runtime Operator;CT_RO;Major +google-upgrade-googletest-case;google;upgrade-googletest-case;Upgrade Googletest Case;CT_UGC;Major +hicpp-avoid-c-arrays;hicpp;avoid-c-arrays;Avoid C Arrays;CT_ACA_2;Major +hicpp-avoid-goto;hicpp;avoid-goto;Avoid Goto;CT_AG_2;Major +hicpp-braces-around-statements;hicpp;braces-around-statements;Braces Around Statements;CT_BAS;Major +hicpp-deprecated-headers;hicpp;deprecated-headers;Deprecated Headers;CT_DH_2;Major +hicpp-exception-baseclass;hicpp;exception-baseclass;Exception Baseclass;CT_EB;Major +hicpp-explicit-conversions;hicpp;explicit-conversions;Explicit Conversions;CT_EC_9;Major +hicpp-function-size;hicpp;function-size;Function Size;CT_FS;Major +hicpp-invalid-access-moved;hicpp;invalid-access-moved;Invalid Access Moved;CT_IAM;Major +hicpp-member-init;hicpp;member-init;Member Init;CT_MI_2;Major +hicpp-move-const-arg;hicpp;move-const-arg;Move Const Arg;CT_MCA;Major +hicpp-multiway-paths-covered;hicpp;multiway-paths-covered;Multiway Paths Covered;CT_MPC;Major +hicpp-named-parameter;hicpp;named-parameter;Named Parameter;CT_NP;Major +hicpp-new-delete-operators;hicpp;new-delete-operators;New Delete Operators;CT_NDO;Major +hicpp-no-array-decay;hicpp;no-array-decay;No Array Decay;CT_NAD;Major +hicpp-no-assembler;hicpp;no-assembler;No Assembler;CT_NA;Major +hicpp-no-malloc;hicpp;no-malloc;No Malloc;CT_NM_2;Major +hicpp-noexcept-move;hicpp;noexcept-move;Noexcept Move;CT_NM_3;Major +hicpp-signed-bitwise;hicpp;signed-bitwise;Signed Bitwise;CT_SB;Major +hicpp-special-member-functions;hicpp;special-member-functions;Special Member Functions;CT_SMF_2;Major +hicpp-static-assert;hicpp;static-assert;Static Assert;CT_SA_2;Major +hicpp-undelegated-constructor;hicpp;undelegated-constructor;Undelegated Constructor;CT_UC_2;Major +hicpp-uppercase-literal-suffix;hicpp;uppercase-literal-suffix;Uppercase Literal Suffix;CT_ULS;Major +hicpp-use-auto;hicpp;use-auto;Use Auto;CT_UA;Major +hicpp-use-emplace;hicpp;use-emplace;Use Emplace;CT_UE;Major +hicpp-use-equals-default;hicpp;use-equals-default;Use Equals Default;CT_UED;Major +hicpp-use-equals-delete;hicpp;use-equals-delete;Use Equals Delete;CT_UED_2;Major +hicpp-use-noexcept;hicpp;use-noexcept;Use Noexcept;CT_UN;Major +hicpp-use-nullptr;hicpp;use-nullptr;Use Nullptr;CT_UN_2;Major +hicpp-use-override;hicpp;use-override;Use Override;CT_UO;Major +hicpp-vararg;hicpp;vararg;Vararg;CT_V;Major +linuxkernel-must-use-errs;linuxkernel;must-use-errs;Must Use Errs;CT_MUE;Major +llvm-else-after-return;llvm;else-after-return;Else After Return;CT_EAR;Major +llvm-header-guard;llvm;header-guard;Header Guard;CT_HG;Major +llvm-include-order;llvm;include-order;Include Order;CT_IO;Major +llvm-namespace-comment;llvm;namespace-comment;Namespace Comment;CT_NC_2;Major +llvm-prefer-isa-or-dyn-cast-in-conditionals;llvm;prefer-isa-or-dyn-cast-in-conditionals;Prefer Isa Or Dyn Cast In Conditionals;CT_PIODCIC;Major +llvm-prefer-register-over-unsigned;llvm;prefer-register-over-unsigned;Prefer Register Over Unsigned;CT_PROU;Major +llvm-qualified-auto;llvm;qualified-auto;Qualified Auto;CT_QA;Major +llvm-twine-local;llvm;twine-local;Twine Local;CT_TL;Major +llvmlibc-callee-namespace;llvmlibc;callee-namespace;Callee Namespace;CT_CN;Major +llvmlibc-implementation-in-namespace;llvmlibc;implementation-in-namespace;Implementation In Namespace;CT_IIN;Major +llvmlibc-restrict-system-libc-headers;llvmlibc;restrict-system-libc-headers;Restrict System Libc Headers;CT_RSLH;Major +misc-definitions-in-headers;misc;definitions-in-headers;Definitions In Headers;CT_DIH;Major +misc-misplaced-const;misc;misplaced-const;Misplaced Const;CT_MC_6;Major +misc-new-delete-overloads;misc;new-delete-overloads;New Delete Overloads;CT_NDO_2;Major +misc-no-recursion;misc;no-recursion;No Recursion;CT_NR;Major +misc-non-copyable-objects;misc;non-copyable-objects;Non Copyable Objects;CT_NCO;Major +misc-non-private-member-variables-in-classes;misc;non-private-member-variables-in-classes;Non Private Member Variables In Classes;CT_NPMVIC_2;Major +misc-redundant-expression;misc;redundant-expression;Redundant Expression;CT_RE;Major +misc-static-assert;misc;static-assert;Static Assert;CT_SA_3;Major +misc-throw-by-value-catch-by-reference;misc;throw-by-value-catch-by-reference;Throw By Value Catch By Reference;CT_TBVCBR;Major +misc-unconventional-assign-operator;misc;unconventional-assign-operator;Unconventional Assign Operator;CT_UAO;Major +misc-uniqueptr-reset-release;misc;uniqueptr-reset-release;Uniqueptr Reset Release;CT_URR;Major +misc-unused-alias-decls;misc;unused-alias-decls;Unused Alias Decls;CT_UAD;Major +misc-unused-parameters;misc;unused-parameters;Unused Parameters;CT_UP;Major +misc-unused-using-decls;misc;unused-using-decls;Unused Using Decls;CT_UUD;Major +modernize-avoid-bind;modernize;avoid-bind;Avoid Bind;CT_AB;Major +modernize-avoid-c-arrays;modernize;avoid-c-arrays;Avoid C Arrays;CT_ACA_3;Major +modernize-concat-nested-namespaces;modernize;concat-nested-namespaces;Concat Nested Namespaces;CT_CNN;Major +modernize-deprecated-headers;modernize;deprecated-headers;Deprecated Headers;CT_DH_3;Major +modernize-deprecated-ios-base-aliases;modernize;deprecated-ios-base-aliases;Deprecated Ios Base Aliases;CT_DIBA;Major +modernize-loop-convert;modernize;loop-convert;Loop Convert;CT_LC;Major +modernize-make-shared;modernize;make-shared;Make Shared;CT_MS;Major +modernize-make-unique;modernize;make-unique;Make Unique;CT_MU_3;Major +modernize-pass-by-value;modernize;pass-by-value;Pass By Value;CT_PBV;Major +modernize-raw-string-literal;modernize;raw-string-literal;Raw String Literal;CT_RSL;Major +modernize-redundant-void-arg;modernize;redundant-void-arg;Redundant Void Arg;CT_RVA;Major +modernize-replace-auto-ptr;modernize;replace-auto-ptr;Replace Auto Ptr;CT_RAP;Major +modernize-replace-disallow-copy-and-assign-macro;modernize;replace-disallow-copy-and-assign-macro;Replace Disallow Copy And Assign Macro;CT_RDCAAM;Major +modernize-replace-random-shuffle;modernize;replace-random-shuffle;Replace Random Shuffle;CT_RRS;Major +modernize-return-braced-init-list;modernize;return-braced-init-list;Return Braced Init List;CT_RBIL;Major +modernize-shrink-to-fit;modernize;shrink-to-fit;Shrink To Fit;CT_STF;Major +modernize-unary-static-assert;modernize;unary-static-assert;Unary Static Assert;CT_USA_2;Major +modernize-use-auto;modernize;use-auto;Use Auto;CT_UA_2;Major +modernize-use-bool-literals;modernize;use-bool-literals;Use Bool Literals;CT_UBL;Major +modernize-use-default;modernize;use-default;Use Default;CT_UD;Major +modernize-use-default-member-init;modernize;use-default-member-init;Use Default Member Init;CT_UDMI;Major +modernize-use-emplace;modernize;use-emplace;Use Emplace;CT_UE_2;Major +modernize-use-equals-default;modernize;use-equals-default;Use Equals Default;CT_UED_3;Major +modernize-use-equals-delete;modernize;use-equals-delete;Use Equals Delete;CT_UED_4;Major +modernize-use-nodiscard;modernize;use-nodiscard;Use Nodiscard;CT_UN_3;Major +modernize-use-noexcept;modernize;use-noexcept;Use Noexcept;CT_UN_4;Major +modernize-use-nullptr;modernize;use-nullptr;Use Nullptr;CT_UN_5;Major +modernize-use-override;modernize;use-override;Use Override;CT_UO_2;Major +modernize-use-trailing-return-type;modernize;use-trailing-return-type;Use Trailing Return Type;CT_UTRT;Major +modernize-use-transparent-functors;modernize;use-transparent-functors;Use Transparent Functors;CT_UTF;Major +modernize-use-uncaught-exceptions;modernize;use-uncaught-exceptions;Use Uncaught Exceptions;CT_UUE;Major +modernize-use-using;modernize;use-using;Use Using;CT_UU;Major +mpi-buffer-deref;mpi;buffer-deref;Buffer Deref;CT_BD;Major +mpi-type-mismatch;mpi;type-mismatch;Type Mismatch;CT_TM;Major +objc-avoid-nserror-init;objc;avoid-nserror-init;Avoid Nserror Init;CT_ANI;Major +objc-dealloc-in-category;objc;dealloc-in-category;Dealloc In Category;CT_DIC;Major +objc-forbidden-subclassing;objc;forbidden-subclassing;Forbidden Subclassing;CT_FS_2;Major +objc-missing-hash;objc;missing-hash;Missing Hash;CT_MH;Major +objc-nsinvocation-argument-lifetime;objc;nsinvocation-argument-lifetime;Nsinvocation Argument Lifetime;CT_NAL;Major +objc-property-declaration;objc;property-declaration;Property Declaration;CT_PD;Major +objc-super-self;objc;super-self;Super Self;CT_SS_2;Major +openmp-exception-escape;openmp;exception-escape;Exception Escape;CT_EE_2;Major +openmp-use-default-none;openmp;use-default-none;Use Default None;CT_UDN;Major +performance-faster-string-find;performance;faster-string-find;Faster String Find;CT_FSF;Major +performance-for-range-copy;performance;for-range-copy;For Range Copy;CT_FRC;Major +performance-implicit-cast-in-loop;performance;implicit-cast-in-loop;Implicit Cast In Loop;CT_ICIL;Major +performance-implicit-conversion-in-loop;performance;implicit-conversion-in-loop;Implicit Conversion In Loop;CT_ICIL_2;Major +performance-inefficient-algorithm;performance;inefficient-algorithm;Inefficient Algorithm;CT_IA;Major +performance-inefficient-string-concatenation;performance;inefficient-string-concatenation;Inefficient String Concatenation;CT_ISC;Major +performance-inefficient-vector-operation;performance;inefficient-vector-operation;Inefficient Vector Operation;CT_IVO;Major +performance-move-const-arg;performance;move-const-arg;Move Const Arg;CT_MCA_2;Major +performance-move-constructor-init;performance;move-constructor-init;Move Constructor Init;CT_MCI;Major +performance-no-automatic-move;performance;no-automatic-move;No Automatic Move;CT_NAM;Major +performance-no-int-to-ptr;performance;no-int-to-ptr;No Int To Ptr;CT_NITP;Major +performance-noexcept-move-constructor;performance;noexcept-move-constructor;Noexcept Move Constructor;CT_NMC;Major +performance-trivially-destructible;performance;trivially-destructible;Trivially Destructible;CT_TD;Major +performance-type-promotion-in-math-fn;performance;type-promotion-in-math-fn;Type Promotion In Math Fn;CT_TPIMF;Major +performance-unnecessary-copy-initialization;performance;unnecessary-copy-initialization;Unnecessary Copy Initialization;CT_UCI;Major +performance-unnecessary-value-param;performance;unnecessary-value-param;Unnecessary Value Param;CT_UVP;Major +portability-restrict-system-includes;portability;restrict-system-includes;Restrict System Includes;CT_RSI;Major +portability-simd-intrinsics;portability;simd-intrinsics;Simd Intrinsics;CT_SI_2;Major +readability-avoid-const-params-in-decls;readability;avoid-const-params-in-decls;Avoid Const Params In Decls;CT_ACPID;Major +readability-braces-around-statements;readability;braces-around-statements;Braces Around Statements;CT_BAS_2;Major +readability-const-return-type;readability;const-return-type;Const Return Type;CT_CRT;Major +readability-container-size-empty;readability;container-size-empty;Container Size Empty;CT_CSE;Major +readability-convert-member-functions-to-static;readability;convert-member-functions-to-static;Convert Member Functions To Static;CT_CMFTS;Major +readability-delete-null-pointer;readability;delete-null-pointer;Delete Null Pointer;CT_DNP;Major +readability-deleted-default;readability;deleted-default;Deleted Default;CT_DD_2;Major +readability-else-after-return;readability;else-after-return;Else After Return;CT_EAR_2;Major +readability-function-cognitive-complexity;readability;function-cognitive-complexity;Function Cognitive Complexity;CT_FCC;Major +readability-function-size;readability;function-size;Function Size;CT_FS_3;Major +readability-identifier-naming;readability;identifier-naming;Identifier Naming;CT_IN;Major +readability-implicit-bool-cast;readability;implicit-bool-cast;Implicit Bool Cast;CT_IBC;Major +readability-implicit-bool-conversion;readability;implicit-bool-conversion;Implicit Bool Conversion;CT_IBC_2;Major +readability-inconsistent-declaration-parameter-name;readability;inconsistent-declaration-parameter-name;Inconsistent Declaration Parameter Name;CT_IDPN;Major +readability-isolate-declaration;readability;isolate-declaration;Isolate Declaration;CT_ID_2;Major +readability-magic-numbers;readability;magic-numbers;Magic Numbers;CT_MN;Major +readability-make-member-function-const;readability;make-member-function-const;Make Member Function Const;CT_MMFC;Major +readability-misleading-indentation;readability;misleading-indentation;Misleading Indentation;CT_MI_3;Major +readability-misplaced-array-index;readability;misplaced-array-index;Misplaced Array Index;CT_MAI;Major +readability-named-parameter;readability;named-parameter;Named Parameter;CT_NP_2;Major +readability-non-const-parameter;readability;non-const-parameter;Non Const Parameter;CT_NCP;Major +readability-qualified-auto;readability;qualified-auto;Qualified Auto;CT_QA_2;Major +readability-redundant-access-specifiers;readability;redundant-access-specifiers;Redundant Access Specifiers;CT_RAS;Major +readability-redundant-control-flow;readability;redundant-control-flow;Redundant Control Flow;CT_RCF;Major +readability-redundant-declaration;readability;redundant-declaration;Redundant Declaration;CT_RD;Major +readability-redundant-function-ptr-dereference;readability;redundant-function-ptr-dereference;Redundant Function Ptr Dereference;CT_RFPD;Major +readability-redundant-member-init;readability;redundant-member-init;Redundant Member Init;CT_RMI;Major +readability-redundant-preprocessor;readability;redundant-preprocessor;Redundant Preprocessor;CT_RP;Major +readability-redundant-smartptr-get;readability;redundant-smartptr-get;Redundant Smartptr Get;CT_RSG;Major +readability-redundant-string-cstr;readability;redundant-string-cstr;Redundant String Cstr;CT_RSC_2;Major +readability-redundant-string-init;readability;redundant-string-init;Redundant String Init;CT_RSI_2;Major +readability-simplify-boolean-expr;readability;simplify-boolean-expr;Simplify Boolean Expr;CT_SBE;Major +readability-simplify-subscript-expr;readability;simplify-subscript-expr;Simplify Subscript Expr;CT_SSE;Major +readability-static-accessed-through-instance;readability;static-accessed-through-instance;Static Accessed Through Instance;CT_SATI;Major +readability-static-definition-in-anonymous-namespace;readability;static-definition-in-anonymous-namespace;Static Definition In Anonymous Namespace;CT_SDIAN;Major +readability-string-compare;readability;string-compare;String Compare;CT_SC_5;Major +readability-uniqueptr-delete-release;readability;uniqueptr-delete-release;Uniqueptr Delete Release;CT_UDR;Major +readability-uppercase-literal-suffix;readability;uppercase-literal-suffix;Uppercase Literal Suffix;CT_ULS_2;Major +readability-use-anyofallof;readability;use-anyofallof;Use Anyofallof;CT_UA_3;Major +zircon-temporary-objects;zircon;temporary-objects;Temporary Objects;CT_TO;Major +clang-analyzer-core.CallAndMessage;clang-analyzer-core;CallAndMessage;Call And Message;CT_SA_CCAM;Major +clang-analyzer-core.DivideZero;clang-analyzer-core;DivideZero;Divide Zero;CT_SA_CDZ;Major +clang-analyzer-core.NonNullParamChecker;clang-analyzer-core;NonNullParamChecker;Non Null Param Checker;CT_SA_CNNPC;Major +clang-analyzer-core.NullDereference;clang-analyzer-core;NullDereference;Null Dereference;CT_SA_CND;Major +clang-analyzer-core.StackAddressEscape;clang-analyzer-core;StackAddressEscape;Stack Address Escape;CT_SA_CSAE;Major +clang-analyzer-core.UndefinedBinaryOperatorResult;clang-analyzer-core;UndefinedBinaryOperatorResult;Undefined Binary Operator Result;CT_SA_CUBOR;Major +clang-analyzer-core.VLASize;clang-analyzer-core;VLASize;VLA Size;CT_SA_CVS;Major +clang-analyzer-core.uninitialized.ArraySubscript;clang-analyzer-core.uninitialized;ArraySubscript;Array Subscript;CT_SA_CUAS;Major +clang-analyzer-core.uninitialized.Assign;clang-analyzer-core.uninitialized;Assign;Assign;CT_SA_CUA;Major +clang-analyzer-core.uninitialized.Branch;clang-analyzer-core.uninitialized;Branch;Branch;CT_SA_CUB;Major +clang-analyzer-core.uninitialized.CapturedBlockVariable;clang-analyzer-core.uninitialized;CapturedBlockVariable;Captured Block Variable;CT_SA_CUCBV;Major +clang-analyzer-core.uninitialized.UndefReturn;clang-analyzer-core.uninitialized;UndefReturn;Undef Return;CT_SA_CUUR;Major +clang-analyzer-cplusplus.InnerPointer;clang-analyzer-cplusplus;InnerPointer;Inner Pointer;CT_SA_CIP;Major +clang-analyzer-cplusplus.NewDelete;clang-analyzer-cplusplus;NewDelete;New Delete;CT_SA_CND_2;Major +clang-analyzer-cplusplus.NewDeleteLeaks;clang-analyzer-cplusplus;NewDeleteLeaks;New Delete Leaks;CT_SA_CNDL;Major +clang-analyzer-cplusplus.PlacementNewChecker;clang-analyzer-cplusplus;PlacementNewChecker;Placement New Checker;CT_SA_CPNC;Major +clang-analyzer-cplusplus.SelfAssignment;clang-analyzer-cplusplus;SelfAssignment;Self Assignment;CT_SA_CSA;Major +clang-analyzer-deadcode.DeadStores;clang-analyzer-deadcode;DeadStores;Dead Stores;CT_SA_DDS;Major +clang-analyzer-nullability.NullPassedToNonnull;clang-analyzer-nullability;NullPassedToNonnull;Null Passed To Nonnull;CT_SA_NNPTN;Major +clang-analyzer-nullability.NullReturnedFromNonnull;clang-analyzer-nullability;NullReturnedFromNonnull;Null Returned From Nonnull;CT_SA_NNRFN;Major +clang-analyzer-nullability.NullableDereferenced;clang-analyzer-nullability;NullableDereferenced;Nullable Dereferenced;CT_SA_NND;Major +clang-analyzer-nullability.NullablePassedToNonnull;clang-analyzer-nullability;NullablePassedToNonnull;Nullable Passed To Nonnull;CT_SA_NNPTN_2;Major +clang-analyzer-nullability.NullableReturnedFromNonnull;clang-analyzer-nullability;NullableReturnedFromNonnull;Nullable Returned From Nonnull;CT_SA_NNRFN_2;Major +clang-analyzer-optin.cplusplus.UninitializedObject;clang-analyzer-optin.cplusplus;UninitializedObject;Uninitialized Object;CT_SA_OCUO;Major +clang-analyzer-optin.cplusplus.VirtualCall;clang-analyzer-optin.cplusplus;VirtualCall;Virtual Call;CT_SA_OCVC;Major +clang-analyzer-optin.mpi.MPI-Checker;clang-analyzer-optin.mpi;MPI-Checker;MPI-Checker;CT_SA_OMM;Major +clang-analyzer-optin.osx.cocoa.localizability.EmptyLocalizationContextChecker;clang-analyzer-optin.osx.cocoa.localizability;EmptyLocalizationContextChecker;Empty Localization Context Checker;CT_SA_OOCLELCC;Major +clang-analyzer-optin.osx.cocoa.localizability.NonLocalizedStringChecker;clang-analyzer-optin.osx.cocoa.localizability;NonLocalizedStringChecker;Non Localized String Checker;CT_SA_OOCLNLSC;Major +clang-analyzer-optin.performance.GCDAntipattern;clang-analyzer-optin.performance;GCDAntipattern;GCD Antipattern;CT_SA_OPGA;Major +clang-analyzer-optin.performance.Padding;clang-analyzer-optin.performance;Padding;Padding;CT_SA_OPP;Major +clang-analyzer-optin.portability.UnixAPI;clang-analyzer-optin.portability;UnixAPI;Unix API;CT_SA_OPUA;Major +clang-analyzer-security.FloatLoopCounter;clang-analyzer-security;FloatLoopCounter;Float Loop Counter;CT_SA_SFLC;Major +clang-analyzer-security.insecureAPI.UncheckedReturn;clang-analyzer-security.insecureAPI;UncheckedReturn;Unchecked Return;CT_SA_SIUR;Major +clang-analyzer-security.insecureAPI.bcmp;clang-analyzer-security.insecureAPI;bcmp;bcmp;CT_SA_SIB;Major +clang-analyzer-security.insecureAPI.bcopy;clang-analyzer-security.insecureAPI;bcopy;bcopy;CT_SA_SIB_2;Major +clang-analyzer-security.insecureAPI.bzero;clang-analyzer-security.insecureAPI;bzero;bzero;CT_SA_SIB_3;Major +clang-analyzer-security.insecureAPI.getpw;clang-analyzer-security.insecureAPI;getpw;getpw;CT_SA_SIG;Major +clang-analyzer-security.insecureAPI.gets;clang-analyzer-security.insecureAPI;gets;gets;CT_SA_SIG_2;Major +clang-analyzer-security.insecureAPI.mkstemp;clang-analyzer-security.insecureAPI;mkstemp;mkstemp;CT_SA_SIM;Major +clang-analyzer-security.insecureAPI.mktemp;clang-analyzer-security.insecureAPI;mktemp;mktemp;CT_SA_SIM_2;Major +clang-analyzer-security.insecureAPI.rand;clang-analyzer-security.insecureAPI;rand;rand;CT_SA_SIR;Major +clang-analyzer-security.insecureAPI.strcpy;clang-analyzer-security.insecureAPI;strcpy;strcpy;CT_SA_SIS;Major +clang-analyzer-security.insecureAPI.vfork;clang-analyzer-security.insecureAPI;vfork;vfork;CT_SA_SIV;Major +clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling;clang-analyzer-security.insecureAPI;DeprecatedOrUnsafeBufferHandling;Deprecated Or Unsafe Buffer Handling;CT_SA_SIDOUBH;Major +clang-analyzer-unix.API;clang-analyzer-unix;API;API;CT_SA_UA;Major +clang-analyzer-unix.Malloc;clang-analyzer-unix;Malloc;Malloc;CT_SA_UM;Major +clang-analyzer-unix.MallocSizeof;clang-analyzer-unix;MallocSizeof;Malloc Sizeof;CT_SA_UMS;Major +clang-analyzer-unix.MismatchedDeallocator;clang-analyzer-unix;MismatchedDeallocator;Mismatched Deallocator;CT_SA_UMD;Major +clang-analyzer-unix.Vfork;clang-analyzer-unix;Vfork;Vfork;CT_SA_UV;Major +clang-analyzer-unix.cstring.BadSizeArg;clang-analyzer-unix.cstring;BadSizeArg;Bad Size Arg;CT_SA_UCBSA;Major +clang-analyzer-unix.cstrisng.NullArg;clang-analyzer-unix.cstrisng;NullArg;Null Arg;CT_SA_UCNA;Major +clang-analyzer-osx.API;clang-analyzer-osx;API;API;CT_SA_OA;Major +clang-analyzer-osx.NumberObjectConversion;clang-analyzer-osx;NumberObjectConversion;Number Object Conversion;CT_SA_ONOC;Major +clang-analyzer-osx.ObjCProperty;clang-analyzer-osx;ObjCProperty;Obj C Property;CT_SA_OOCP;Major +clang-analyzer-osx.SecKeychainAPI;clang-analyzer-osx;SecKeychainAPI;Sec Keychain API;CT_SA_OSKA;Major +clang-analyzer-osx.cocoa.AtSync;clang-analyzer-osx.cocoa;AtSync;At Sync;CT_SA_OCAS;Major +clang-analyzer-osx.cocoa.AutoreleaseWrite;clang-analyzer-osx.cocoa;AutoreleaseWrite;Autorelease Write;CT_SA_OCAW;Major +clang-analyzer-osx.cocoa.ClassRelease;clang-analyzer-osx.cocoa;ClassRelease;Class Release;CT_SA_OCCR;Major +clang-analyzer-osx.cocoa.Dealloc;clang-analyzer-osx.cocoa;Dealloc;Dealloc;CT_SA_OCD;Major +clang-analyzer-osx.cocoa.IncompatibleMethodTypes;clang-analyzer-osx.cocoa;IncompatibleMethodTypes;Incompatible Method Types;CT_SA_OCIMT;Major +clang-analyzer-osx.cocoa.Loops;clang-analyzer-osx.cocoa;Loops;Loops;CT_SA_OCL;Major +clang-analyzer-osx.cocoa.MissingSuperCall;clang-analyzer-osx.cocoa;MissingSuperCall;Missing Super Call;CT_SA_OCMSC;Major +clang-analyzer-osx.cocoa.NSAutoreleasePool;clang-analyzer-osx.cocoa;NSAutoreleasePool;NS Autorelease Pool;CT_SA_OCNAP;Major +clang-analyzer-osx.cocoa.NSError;clang-analyzer-osx.cocoa;NSError;NS Error;CT_SA_OCNE;Major +clang-analyzer-osx.cocoa.NilArg;clang-analyzer-osx.cocoa;NilArg;Nil Arg;CT_SA_OCNA;Major +clang-analyzer-osx.cocoa.NonNilReturnValue;clang-analyzer-osx.cocoa;NonNilReturnValue;Non Nil Return Value;CT_SA_OCNNRV;Major +clang-analyzer-osx.cocoa.ObjCGenerics;clang-analyzer-osx.cocoa;ObjCGenerics;Obj C Generics;CT_SA_OCOCG;Major +clang-analyzer-osx.cocoa.RetainCount;clang-analyzer-osx.cocoa;RetainCount;Retain Count;CT_SA_OCRC;Major +clang-analyzer-osx.cocoa.RunLoopAutoreleaseLeak;clang-analyzer-osx.cocoa;RunLoopAutoreleaseLeak;Run Loop Autorelease Leak;CT_SA_OCRLAL;Major +clang-analyzer-osx.cocoa.SelfInit;clang-analyzer-osx.cocoa;SelfInit;Self Init;CT_SA_OCSI;Major +clang-analyzer-osx.cocoa.SuperDealloc;clang-analyzer-osx.cocoa;SuperDealloc;Super Dealloc;CT_SA_OCSD;Major +clang-analyzer-osx.cocoa.UnusedIvars;clang-analyzer-osx.cocoa;UnusedIvars;Unused Ivars;CT_SA_OCUI;Major +clang-analyzer-osx.cocoa.VariadicMethodTypes;clang-analyzer-osx.cocoa;VariadicMethodTypes;Variadic Method Types;CT_SA_OCVMT;Major +clang-analyzer-osx.coreFoundation.CFError;clang-analyzer-osx.coreFoundation;CFError;CF Error;CT_SA_OCCE;Major +clang-analyzer-osx.coreFoundation.CFNumber;clang-analyzer-osx.coreFoundation;CFNumber;CF Number;CT_SA_OCCN;Major +clang-analyzer-osx.coreFoundation.CFRetainRelease;clang-analyzer-osx.coreFoundation;CFRetainRelease;CF Retain Release;CT_SA_OCCRR;Major +clang-analyzer-osx.coreFoundation.containers.OutOfBounds;clang-analyzer-osx.coreFoundation.containers;OutOfBounds;Out Of Bounds;CT_SA_OCCOOB;Major +clang-analyzer-osx.coreFoundation.containers.PointerSizedValues;clang-analyzer-osx.coreFoundation.containers;PointerSizedValues;Pointer Sized Values;CT_SA_OCCPSV;Major +clang-analyzer-fuchsia.HandleChecker;clang-analyzer-fuchsia;HandleChecker;Handle Checker;CT_SA_FHC;Major +clang-analyzer-webkit.RefCntblBaseVirtualDtor;clang-analyzer-webkit;RefCntblBaseVirtualDtor;Ref Cntbl Base Virtual Dtor;CT_SA_WRCBVD;Major +clang-analyzer-webkit.NoUncountedMemberChecker;clang-analyzer-webkit;NoUncountedMemberChecker;No Uncounted Member Checker;CT_SA_WNUMC;Major +clang-analyzer-webkit.UncountedLambdaCapturesChecker;clang-analyzer-webkit;UncountedLambdaCapturesChecker;Uncounted Lambda Captures Checker;CT_SA_WULCC;Major diff --git a/cl/ClangTidy2Graph/src/ResultConverter.cpp b/cl/ClangTidy2Graph/src/ResultConverter.cpp new file mode 100644 index 0000000..bbf5305 --- /dev/null +++ b/cl/ClangTidy2Graph/src/ResultConverter.cpp @@ -0,0 +1,373 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include +#include +#include +#include +#include +#include + +#include "../inc/ResultConverter.h" +#include "../inc/messages.h" +#include "../inc/defines.h" + +using namespace std; +using namespace common; +using namespace columbus; +using namespace columbus::graph; +using namespace columbus::clangtidy2graph; + + +ResultConverter::ResultConverter(const std::string& limFileName, const std::string& txtOutFile, const std::string& rulFileName, const std::string& rulConfig, const bool exportRul, const std::string& changePathFrom, const std::string& changePathTo): + handler(), + rulHandler(rulFileName, rulConfig, "eng"), + limStrTable(), + limFactory(limStrTable, "", columbus::lim::asg::limLangOther), + graphIndexer(graphsupport::GraphRangeIndexer::getGraphRangeIndexerInstance()), + changePathFrom(changePathFrom), + changePathTo(changePathTo), + txtOutFile(txtOutFile) +{ + // Loading lim + list headerDataList; + limFactory.load(limFileName, headerDataList); + loadFilter(limFactory, limFileName, ".flim"); + lim2graph::convertBaseGraph(limFactory, graph, true, true, true, true, false); + graphIndexer.turnOn(graph); + if(exportRul) { + graphsupport::buildRulToGraph(graph, rulHandler); + } + + //Debug + // graph.saveXML(common::pathRemoveExtension("base") + ".xml"); + + // Creating empty text output file + if(!txtOutFile.empty()) { + std::ofstream out(txtOutFile.c_str()); + if(!out) { + WriteMsg::write(CMSG_FAILED_TO_OPEN_FILE, txtOutFile.c_str()); + } else { + out << ""; + } + } +} + +ResultConverter::~ResultConverter(){ + WriteMsg::write(WriteMsg::mlNormal, "\nClangTidy2Graph has finished. Some statistics:\n"); + WriteMsg::write(WriteMsg::mlNormal, " not_defined = %4d (Number of warnings that are not defined in our rule file and therefore thrown away)\n", not_defined); + WriteMsg::write(WriteMsg::mlNormal, " invalid_node = %4d (Number of warnings that we cannot attach to any node as either their path or line/col is wrong somehow)\n", invalid_node); + WriteMsg::write(WriteMsg::mlNormal, " not_found = %4d (Number of warnings that we cannot attach to any node for some other reason)\n", not_found); + WriteMsg::write(WriteMsg::mlNormal, " already_added = %4d (Number of warnings that we do not add because it is already added)\n", already_added); + WriteMsg::write(WriteMsg::mlNormal, " unable_to_add = %4d (Number of warnings that we are unable to add for some other reason)\n", unable_to_add); + WriteMsg::write(WriteMsg::mlNormal, " success = %4d (Number of successfully added warnings)\n", success); + WriteMsg::write(WriteMsg::mlNormal, " num_of_warnings = %4d (Total number of warnings)\n\n", num_of_warnings); + + //WriteMsg::write(WriteMsg::mlNormal, "Number of notes: %d\n", num_notes); +} + +void ResultConverter::process(const std::string& resultFileName){ + //TODO XML parsing + loadXml(resultFileName, handler); + //Get list of warnings. + std::list warnings = handler.getWarnings(); + + num_of_warnings += warnings.size(); + for(auto warning : warnings){ + addWarning(warning); + num_notes += warning.notes.size(); + } + handler.clearWarnings(); +} + +void ResultConverter::saveResultGraph(const std::string& graphOutputFilename, bool createXMLdump) { + graph.saveBinary(graphOutputFilename); + if (createXMLdump) { + graph.saveXML(common::pathRemoveExtension(graphOutputFilename) + ".xml"); + } +} + +void ResultConverter::addWarning(Warning& warning){ + string ruleId; + try{ + ruleId = rulHandler.getRuleIdByOriginalId(warning.name); + }catch(rul::RulHandlerException &){ + WriteMsg::write(CMSG_RULE_NOT_DEFINED, warning.name.c_str()); + not_defined++; + return; + } + if (!rulHandler.getIsDefined(ruleId)) { + WriteMsg::write(CMSG_RULE_NOT_DEFINED, warning.name.c_str()); + not_defined++; + return; + } + if (!rulHandler.getIsEnabled(ruleId)) { + not_defined++; + return; //rule is not enabled + } + + list nodes; + + // Set up proper path format + warning.file = common::pathCanonicalize(warning.file); + + // this patches up the problem of paths starting with C: here but c: in the LIM... but its not the best fix... + LowerDriveLetterOnWindows(warning.file); + + common::changePath(warning.file, changePathFrom, changePathTo); + + if (graphIndexer.findNodesByRange(graph, warning.file, warning.line, 0, warning.line, INT_MAX, nodes)) { + int minDist = INT_MAX; + Node node; + + // Find the closest one + for(list::iterator it = nodes.begin(); it != nodes.end(); ++it) { + vector positions; + graphsupport::getPositionAttributes(*it, positions); + + int lMinDist = INT_MAX;//debug + for(vector::iterator pos = positions.begin(); pos != positions.end(); ++pos){ + if(pos->path.compare(warning.file) == 0){ + //Namespace erroroknál a col position sokszor a namespace után van. Ezért a findeNodesByRande függvényt nem + //0 col-lal hívjuk, hanem a warning-hoz tartozó értékkel, akkor lesznek olyan hibák, amelyekhez nem talál node-ot. + //távolság számításkor ezt figyelembe kell venni. + + if( ((abs(warning.line - pos->line) + abs(warning.line - pos->endline)) + (abs(warning.column - pos->col) + abs(warning.column - pos->endcol))) < minDist ) { + node = *it; + minDist = abs(warning.line - pos->line) + abs(warning.line - pos->endline) + abs(warning.column - pos->col) + abs(warning.column - pos->endcol); + } + //debug + if( ((abs(warning.line - pos->line) + abs(warning.line - pos->endline)) + (abs(warning.column - pos->col) + abs(warning.column - pos->endcol))) < lMinDist ) { + lMinDist = abs(warning.line - pos->line) + abs(warning.line - pos->endline) + abs(warning.column - pos->col) + abs(warning.column - pos->endcol); + } + + } + } + // cout << it->getUID() << ": " << lMinDist << endl; //debug + } + + // cout << endl; + //cout << "Found nodes: " << nodes.size() << endl << endl; + + // If the found node is an attribute, we use its parent + if(node != Graph::invalidNode) { + if(node.getType().getType() == graphsupport::graphconstants::NTYPE_LIM_ATTRIBUTE){ + Edge::EdgeIterator edgeIt = node.findOutEdges(Edge::EdgeType(graphsupport::graphconstants::ETYPE_LIM_LOGICALTREE, Edge::edtReverse)); + if(edgeIt.hasNext()) { + node = edgeIt.next().getToNode(); + } + } + } + + if (node != Graph::invalidNode) { + bool warningAdded = false; + + // If there are notes, then we adding them as extraInfo attribute + if( warning.notes.size() != 0){ + AttributeComposite extraInfo = graph.createAttributeComposite(graphsupport::graphconstants::ATTR_EXTRAINFO, graphsupport::graphconstants::CONTEXT_TRACE); + for(list::iterator it = warning.notes.begin(); it != warning.notes.end(); ++it) + { + common::changePath(it->file, changePathFrom, changePathTo); + AttributeComposite sl = graph.createAttributeComposite(graphsupport::graphconstants::ATTR_SOURCELINK, ""); + sl.addAttribute(graph.createAttributeString(graphsupport::graphconstants::ATTR_PATH, "", it->file)); + sl.addAttribute(graph.createAttributeInt(graphsupport::graphconstants::ATTR_LINE, "", it->line)); + sl.addAttribute(graph.createAttributeInt(graphsupport::graphconstants::ATTR_COLUMN, "", it->column)); + sl.addAttribute(graph.createAttributeInt(graphsupport::graphconstants::ATTR_ENDLINE, "", it->line)); + sl.addAttribute(graph.createAttributeInt(graphsupport::graphconstants::ATTR_ENDCOLUMN, "", it->column)); + sl.addAttribute(graph.createAttributeString(graphsupport::graphconstants::ATTR_WARNINGTEXT, "", it->message)); + extraInfo.addAttribute(sl); + } + + warningAdded = graphsupport::addWarningOnce(graph, node, ruleId, warning.file, warning.line, warning.column, warning.line, 10000, warning.message, extraInfo, &warningCache); + }else{ + warningAdded = graphsupport::addWarningOnce(graph, node, ruleId, warning.file, warning.line, warning.column, warning.line, 10000, warning.message, &warningCache); + } + if (warningAdded){ + success++; + if(!txtOutFile.empty()) { + std::ofstream out(txtOutFile.c_str(), std::ofstream::out | std::ofstream::app); + if(!out) { + WriteMsg::write(CMSG_FAILED_TO_OPEN_FILE, txtOutFile.c_str()); + }else{ + out << warning.file << "(" << warning.line << "): " << ruleId << ": " << warning.message << std::endl; + } + } + }else{ + //Unable to add + Attribute::AttributeIterator it = node.findAttributeByName(ruleId); + if(!it.hasNext()){ + unable_to_add++; + WriteMsg::write(CMSG_UNABLE_TO_ADD_WARNING_AT_LOCATION, warning.file.c_str(), warning.line); + } + else{ + already_added++; + } + } + + } + else + { + //[DEBUG] a teljes else ág + invalid_node++; +// std::ofstream out("invalid_node.txt", std::ofstream::out | std::ofstream::app); +// if(!out) { +// WriteMsg::write(CMSG_FAILED_TO_OPEN_FILE, "invalid_node.txt"); +// } +// else +// { +// out << warning.file << "(" << warning.line << "): " << ruleId << ": " << warning.message << std::endl; +// +// for(list::iterator it = nodes.begin(); it != nodes.end(); ++it) { +// vector positions; +// graphsupport::getPositionAttributes(*it, positions); +// for(vector::iterator pos = positions.begin(); pos != positions.end(); ++pos){ +// out << pos->line << " (" << pos->line << " | " << pos->endline << ")" << endl; +// } +// } +// } + } + + } + else + { + //cout << "[DEBUG] Node not found. " << endl; + not_found++; +// std::ofstream out("not_found.txt", std::ofstream::out | std::ofstream::app); +// if(!out) { +// WriteMsg::write(CMSG_FAILED_TO_OPEN_FILE, "not_found.txt"); +// } else { +// out << warning.file << "(" << warning.line << "): " << ruleId << ": " << warning.message << std::endl; +// } + } +} + +void ResultConverter::aggregateWarnings() { + graphsupport::cumSum(graph, graph::Edge::EdgeType(graphsupport::graphconstants::ETYPE_LIM_COMPONENT, graph::Edge::edtDirectional), true); + graphsupport::cumSum(graph, graph::Edge::EdgeType(graphsupport::graphconstants::ETYPE_LIM_COMPONENTTREE, graph::Edge::edtReverse), false); + graphsupport::cumSum(graph, graph::Edge::EdgeType(graphsupport::graphconstants::ETYPE_LIM_LOGICALTREE, graph::Edge::edtReverse), false); + + graphsupport::createGroupMetrics(graph, rulHandler); +} + +//////////////////////////// Handler functions ////////////////// + +void Handler::beginTag(const std::string& name, const AttributeList& list){ + currentTag = name; + if(name.compare(_DIAGNOSTIC) == 0){ + //insert new warning + Warning warning; + warning.line = 0; + warning.column = 0; + warning.file = ""; + warning.message = ""; + warning.name = ""; + warnings.push_back(warning); + + hasToSkip = false; + }else if(name.compare(_DIAGNOSTIC_NOTE) == 0){ + isNote = true; + Note note; + note.line = 0; + note.column = 0; + note.file = ""; + note.message = ""; + + // If the warning has an invalid line, then content handler removes it. + // Due to that the warnings can be empty here. + if (!warnings.empty()) + warnings.back().notes.push_back(note); + } +} + +void Handler::content(const std::string& content){ + if(!hasToSkip){ + if(currentTag.compare(_DIAGNOSTIC_LOCATION_FILE) == 0){ + if(isNote) + warnings.back().notes.back().file = content; + else + warnings.back().file = content; + }else if(currentTag.compare(_DIAGNOSTIC_LOCATION_LINE) == 0){ + //Invalid location + if(std::stoi(content) > 0){ + if(isNote) + warnings.back().notes.back().line = std::stoi(content); + else + warnings.back().line = std::stoi(content); + }else{ + if(isNote) + warnings.back().notes.pop_back(); + else + warnings.pop_back(); + + hasToSkip = true; + } + }else if(currentTag.compare(_DIAGNOSTIC_LOCATION_COLUMN) == 0){ + //Invalid location + if(std::stoi(content) > 0){ + if(isNote) + warnings.back().notes.back().column = std::stoi(content); + else + warnings.back().column = std::stoi(content); + }else{ + if(isNote) + warnings.back().notes.back().column = 0; + else + warnings.back().column = 0; + } + }else if(currentTag.compare(_DIAGNOSTIC_MSG) == 0){ + if(isNote) + warnings.back().notes.back().message = resolveEscapeChars(content); + else + warnings.back().message = resolveEscapeChars(content); + }else if(currentTag.compare(_DIAGNOSTIC_NAME) == 0){ + warnings.back().name = content; + } + } +} + +void Handler::endTag(const std::string& name){ + currentTag = ""; + if(name.compare(_DIAGNOSTIC_NOTE) == 0) + isNote = false; +} + +std::list Handler::getWarnings(){ + return warnings; +} + +void Handler::clearWarnings(){ + warnings.clear(); +} + +std::string Handler::resolveEscapeChars(std::string content){ + vector> escapeChars; + escapeChars.push_back(make_pair(regex("&"), "&")); + escapeChars.push_back(make_pair(regex(">"), ">")); + escapeChars.push_back(make_pair(regex("<"), "<")); + escapeChars.push_back(make_pair(regex("'"), "\'")); + escapeChars.push_back(make_pair(regex("""), "\"")); + escapeChars.push_back(make_pair(regex("\\n"), "\n")); + for(auto it : escapeChars){ + content = regex_replace(content,it.first,it.second); + } + return content; +} + +Handler::~Handler(){} diff --git a/cl/ClangTidy2Graph/src/main.cpp b/cl/ClangTidy2Graph/src/main.cpp new file mode 100644 index 0000000..2e00292 --- /dev/null +++ b/cl/ClangTidy2Graph/src/main.cpp @@ -0,0 +1,222 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#define PROGRAM_NAME "ClangTidy2Graph" +#define EXECUTABLE_NAME "ClangTidy2Graph" + +#include +#include +#include +#include +#include +#include + +#include "../inc/ResultConverter.h" +#include "../inc/messages.h" + +using namespace std; +using namespace common; +using namespace columbus; +using namespace columbus::clangtidy2graph; + +static string rulesListFileName; +static string outputFileName; +static string limFileName; +static string graphFileName; +static string rul_s = "ClangTidy.rul"; +static string rulConfig = "Default"; +static bool exportRul = false; +static string fList; +static list listOfFile; +static size_t peakMemory = 0; + +static bool ppMakeRul(const Option *o, char *argv[]) { + rulesListFileName = argv[0]; + return true; +} + +static bool ppGraph(const Option *o, char *argv[]) { + graphFileName = argv[0]; + return true; +} + +static bool ppOut(const Option *o, char *argv[]) { + outputFileName = argv[0]; + return true; +} + +static bool ppLimFile(const Option *o, char *argv[]) { + limFileName = argv[0]; + return true; +} + +static bool ppRul (const Option *o, char *argv[]) { + rul_s = argv[0]; + return true; +} + +static bool ppRulConfig (const Option *o, char *argv[]) { + rulConfig = argv[0]; + return true; +} + +static bool ppExportRul(const Option *o, char *argv[]) { + exportRul = true; + return true; +} + +static bool ppList(const Option *o, char *argv[]) { + fList = argv[0]; + return true; +} + +static void ppFile(char *filename) { + listOfFile.push_back(filename); +} + +const common::Option OPTIONS_OBJ [] = { + { false, "-makerul", 1, "rules.csv", 0, OT_WS, ppMakeRul, NULL, "Making rul file from the rules.csv file."}, + { false, "-graph", 1, "filename", 0, OT_WC, ppGraph, NULL, "Save binary graph output."}, + { false, "-out", 1, "filename", 0, OT_WC, ppOut, NULL, "Specify the name of the output file. The list of rule violations will be dumped in it.\n"}, + CL_INPUT_LIST + CL_LIM + CL_RUL_AND_RULCONFIG("ClangTidy.rul") + CL_EXPORTRUL + COMMON_CL_ARGS +}; + +static inline void updateMemStat(size_t *max_mem) { + memstat ms = getProcessUsedMemSize(); + if (*max_mem < ms.size) { + *max_mem = ms.size; + } +} + +int main(int argc, char* argv[]) { + int ret = EXIT_SUCCESS; + MAIN_BEGIN + + MainInit(argc, argv, "-"); + + if( !rulesListFileName.empty() ){ + // Process the rules.csv and generate the rul. + io::CsvIO csv(rulesListFileName, io::IOBase::omRead); //Open CSV + csv.setSeparator(';'); + + rul::RulHandler rulHandler(rulConfig, "eng"); + rulHandler.setToolDescription("ID", "ClangTidy"); + + list line; + int num_of_lines = 0; + + while(csv.readLine(line)){ + num_of_lines++; + if(num_of_lines > 1){ + //Reading csv + string priority = line.back(); + line.pop_back(); //Priority + string check_id = line.back(); + line.pop_back(); //ID + string display_name = line.back(); + line.pop_back(); //New name + line.pop_back(); //Old name + string group = line.back(); + line.pop_back(); //Group + string full_name = line.back(); + + + // Check does group exist + if(!rulHandler.getIsDefined(group)){ + // insert new group metric + rulHandler.defineMetric(group); + rulHandler.createConfiguration(group, rulHandler.getConfig()); + rulHandler.createLanguage(group, "eng"); + rulHandler.setGroupType(group, "summarized"); + rulHandler.setDisplayName(group, group); + rulHandler.setHasWarningText(group, true); + rulHandler.setIsEnabled(group, true); + rulHandler.setIsVisible(group, true); + rulHandler.setHelpText(group,""); + + } + + //insert new check metric + rulHandler.defineMetric(check_id); + rulHandler.createConfiguration(check_id, rulHandler.getConfig()); + rulHandler.setIsEnabled(check_id, true); + rulHandler.createLanguage(check_id, "eng"); + rulHandler.setHasWarningText(check_id, true); + rulHandler.setGroupType(check_id, "false"); + rulHandler.addMetricGroupMembers(check_id, group); + rulHandler.setSettingValue(check_id, "Priority", priority, true); + rulHandler.setDisplayName(check_id, display_name); + rulHandler.setOriginalId(check_id, full_name); + + } + line.erase(line.begin(), line.end()); + + } + + csv.close(); + rulHandler.saveRul(rul_s); + + }else { + + // TODO Process the xml outputs of the ClangTidy + + // ... + + loadStringListFromFile(fList, listOfFile); + // Missing input file. + if (listOfFile.empty()) { + WriteMsg::write(CMSG_NO_INPUT_FILE); + clError(); + } + // Missing output filename. + if (graphFileName.empty()) { + WriteMsg::write(CMSG_NO_OUTPUT_FILE); + clError(); + } + ResultConverter converter(limFileName, outputFileName, rul_s, rulConfig, exportRul, "", ""); + updateMemStat(&peakMemory); + for(list::iterator file = listOfFile.begin(); file != listOfFile.end(); ++file){ + string ctFilePath = *file + ".ct.err"; + if(pathFileExists(ctFilePath, false)){ + WriteMsg::write(WriteMsg::mlNormal, "Loading warnings from file: %s\n", ctFilePath.c_str()); + converter.process(ctFilePath); + }else{ + // If a compilation unit does not contain a warning, the ct.err file will NOT be generated either + WriteMsg::write(WriteMsg::mlNormal, "No warnings for file: %s\n", (*file).c_str()); + } + } + + updateMemStat(&peakMemory); + converter.aggregateWarnings(); + converter.saveResultGraph(graphFileName, /*xml_dump=*/false); + + // ... + + updateMemStat(&peakMemory); + } + + MAIN_END + + return ret; +} diff --git a/cl/Cppcheck2Graph/CMakeLists.txt b/cl/Cppcheck2Graph/CMakeLists.txt new file mode 100644 index 0000000..321cc6d --- /dev/null +++ b/cl/Cppcheck2Graph/CMakeLists.txt @@ -0,0 +1,21 @@ +set (PROGRAM_NAME Cppcheck2Graph) + +set (SOURCES + src/main.cpp + src/ResultConverter.cpp + src/RuleConverter.cpp + src/XMLParser.cpp + + inc/defines.h + inc/messages.h + inc/ResultConverter.h + inc/RuleConverter.h + inc/XMLParser.h +) + +add_executable(${PROGRAM_NAME} ${SOURCES}) +add_dependencies(${PROGRAM_NAME} ${COLUMBUS_GLOBAL_DEPENDENCY}) +target_link_libraries(${PROGRAM_NAME} lim2graph graphsupport lim graph rul common csi strtable io ${COMMON_EXTERNAL_LIBRARIES}) +add_copy_next_to_the_binary_dependency(${PROGRAM_NAME} Cppcheck.rul) +set_visual_studio_project_folder(${PROGRAM_NAME} TRUE) + diff --git a/cl/Cppcheck2Graph/Cppcheck.rul b/cl/Cppcheck2Graph/Cppcheck.rul new file mode 100644 index 0000000..ea7140d --- /dev/null +++ b/cl/Cppcheck2Graph/Cppcheck.rul @@ -0,0 +1,6044 @@ + + + + + + Cppcheck + + + + + + + + true + true + summarized + + true + API Rules + The API Ruleset contains rules that find built in function usages that are wrong. + The API Ruleset contains rules that find built in function usages that are wrong. + + + + + + + + + true + true + summarized + + true + Boost Library Rules + The Boost Library Ruleset contains rules for boost usage. + The Boost Library Ruleset contains rules for boost usage. + + + + + + + + + true + true + summarized + + true + Buffer Overrun Rules + The Buffer Overrun Ruleset contains rules that find mistakes about buffers usage and array indices. + The Buffer Overrun Ruleset contains rules that find mistakes about buffers usage and array indices. + + + + + + + + + true + false + AssignmentAddressToInteger + Portability Rules + + true + Assignment Address To Integer + + Assigning a pointer to an integer (int/long/etc) is not portable across different platforms and compilers. For example in 32-bit Windows and linux they are same width, but in 64-bit Windows and linux they are of different width. In worst case you end up assigning 64-bit address to 32-bit integer. The safe way is to store addresses only in pointer types (or typedefs like uintptr_t). + + + + Minor + + + + + + + true + false + assignBoolToFloat + Performance Rules + Simple Type Rules + + true + Assign Bool To Float + + Boolean value assigned to floating point variable. + + + + Minor + + + + + + + true + false + assignBoolToPointer + Simple Type Rules + + true + Assign Bool To Pointer + + Boolean value assigned to pointer. + + + + Blocker + + + + + + + true + false + accessForwarded + Memory Handling Rules + + true + Access Forwarded + + Access of forwarded variable 'v'. + + + + Critical + + + + + + + true + false + assignmentInAssert + Side Effect Rules + + true + Assignment In Assert + + Variable 'var' is modified inside assert statement. Assert statements are removed from release builds so the code inside assert statement is not executed. If the code is needed also in release builds, this is a bug. + + + + Critical + + + + + + + true + false + assignmentInCondition + Suspicious Construct Rules + + true + Assignment In Condition + + Suspicious assignment in condition. Condition 'x=y' is always true. + + + + Minor + + + + + + + true + false + autovarInvalidDeallocation + Memory Handling Rules + + true + Autovar Invalid Deallocation + + The deallocation of an auto-variable results in undefined behaviour. You should only free memory that has been allocated dynamically. + + + + Blocker + + + + + + + true + false + assignIfError + Conditional Rules + + true + Assign If Error + + Mismatching assignment and comparison, comparison '' is always false. + + + + Minor + + + + + + + true + false + arrayIndexOutOfBounds + Buffer Overrun Rules + + true + Array Index Out Of Bounds + + Array 'arr[16]' accessed at index 16, which is out of bounds. + + + + Blocker + + + + + + + true + false + arrayIndexOutOfBoundsCond + Buffer Overrun Rules + + true + Array Index Out Of Bounds Cond + + Array 'arr[16]' accessed at index 16, which is out of bounds. + + + + Critical + + + + + + + true + false + AssignmentIntegerToAddress + Portability Rules + + true + Assignment Integer To Address + + Assigning an integer (int/long/etc) to a pointer is not portable across different platforms and compilers. For example in 32-bit Windows and linux they are same width, but in 64-bit Windows and linux they are of different width. In worst case you end up assigning 64-bit integer to 32-bit pointer. The safe way is to store addresses only in pointer types (or typedefs like uintptr_t). + + + + Minor + + + + + + + true + false + arrayIndexThenCheck + Buffer Overrun Rules + + true + Array Index Then Check + + Defensive programming: The variable 'i' is used as an array index before it is checked that is within limits. This can mean that the array might be accessed out of bounds. Reorder conditions such as '(a[i] && i < 10)' to '(i < 10 && a[i])'. That way the array will not be accessed if the index is out of limits. + + + + Minor + + + + + + + true + false + accessMoved + Memory Handling Rules + + true + Access Moved + + Access of moved variable 'v'. + + + + Critical + + + + + + + true + false + arithOperationsOnVoidPointer + Sizeof Operator Rules + + true + Arithmetic Operations On Void Pointer + + 'varname' is of type 'vartype'. When using void pointers in calculations, the behaviour is undefined. Arithmetic operations on 'void *' is a GNU C extension, which defines the 'sizeof(void)' to be 1. + + + + Minor + + + + + + + true + false + operatorEqShouldBeLeftUnimplemented + Object Orientedness Rules + + true + Assignment Operator Should Be Left Unimplemented + + 'operator=' should either return reference to 'this' instance or be declared private and left unimplemented. + + + + Minor + + + + + + + true + false + autoVariables + Memory Handling Rules + + true + Auto Variables + + Dangerous assignment - the function parameter is assigned the address of a local auto-variable. Local auto-variables are reserved from the stack which is freed when the function ends. So the pointer to a local variable is invalid after the function ends. + + + + Blocker + + + + + + + true + false + assertWithSideEffect + Side Effect Rules + + true + Assert With Side Effect + + Non-pure function: 'function' is called inside assert statement. Assert statements are removed from release builds so the code inside assert statement is not executed. If the code is needed also in release builds, this is a bug. + + + + Critical + + + + + + + true + false + bufferAccessOutOfBounds + Buffer Overrun Rules + + true + Buffer Access Out Of Bounds + + Buffer is accessed out of bounds: buf + + + + Blocker + + + + + + + true + false + badBitmaskCheck + Conditional Rules + + true + Bad Bitmask Check + + Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'? + + + + Critical + + + + + + + true + false + boostForeachError + Boost Library Rules + + true + Boost Foreach Error + + BOOST_FOREACH caches the end() iterator. It's undefined behavior if you modify the container inside. + + + + Blocker + + + + + + + true + false + bitwiseOnBoolean + Simple Type Rules + + true + Bitwise On Boolean + + Boolean expression 'expression' is used in bitwise operation. Did you mean '&&'? + + + + Minor + + + + + + + true + false + knownConditionTrueFalse + Conditional Rules + + true + Condition is Always False + + Condition 'x' is always false + + + + Minor + + + + + + + true + false + unknownSignCharArrayIndex + Simple Type Rules + + true + Character Array Index + + 'char' type used as array index. Values greater than 127 will be treated depending on whether 'char' is signed or unsigned on target platform. + + + + Minor + + + + + + + true + false + CastAddressToIntegerAtReturn + Portability Rules + + true + Cast Address To Integer At Return + + Returning an address value in a function with integer (int/long/etc) return type is not portable across different platforms and compilers. For example in 32-bit Windows and Linux they are same width, but in 64-bit Windows and Linux they are of different width. In worst case you end up casting 64-bit address down to 32-bit integer. The safe way is to always return an integer. + + + + Minor + + + + + + + true + false + compareBoolExpressionWithInt + Simple Type Rules + + true + Compare Bool Expression With Int + + Comparison of a boolean expression with an integer other than 0 or 1. + + + + Critical + + + + + + + true + false + charBitOp + Simple Type Rules + + true + Char Bit Op + + When using 'char' variables in bit operations, sign extension can generate unexpected results. For example:\012 char c = 0x80;\012 int i = 0 | c;\012 if (i & 0x8000)\012 printf("not expected");\012The "not expected" will be printed on the screen. + + + + Critical + + + + + + + true + false + copyCtorAndEqOperator + Object Orientedness Rules + + true + Copy Constructor And Eq Operator + + The class 'class' has 'operator=' but lack of 'copy constructor'. + + + + Critical + + + + + + + true + false + clarifyCalculation + Readability and Consistency Rules + + true + Clarify Calculation + + Suspicious calculation. Please use parentheses to clarify the code. The code ''a+b?c:d'' should be written as either ''(a+b)?c:d'' or ''a+(b?c:d)''. + + + + Minor + + + + + + + true + false + checkCastIntToCharAndBack + Simple Type Rules + + true + Check Cast Int To Char And Back + + When saving func_name() return value in char variable there is loss of precision. When func_name() returns EOF this value is truncated. Comparing the char variable with EOF can have unexpected results. For instance a loop "while (EOF != (c = func_name());" loops forever on some compilers/platforms and on other compilers/platforms it will stop when the file contains a matching character. + + + + Critical + + + + + + + true + false + coutCerrMisusage + Input Output Rules + + true + Cout Cerr Misusage + + Invalid usage of output stream: '<< std::cout'. + + + + Blocker + + + + + + + true + false + clarifyCondition + Conditional Rules + + true + Clarify Condition + + Suspicious condition (assignment + comparison); Clarify expression with parentheses. + + + + Minor + + + + + + + true + false + copyCtorPointerCopying + Object Orientedness Rules + + true + Copy Ctor Pointer Copying + + Value of pointer 'var', which points to allocated memory, is copied in copy constructor instead of allocating new memory. + + + + Critical + + + + + + + true + false + comparisonError + Conditional Rules + + true + Comparison Error + + The expression '(X & 0x6) == 0x1' is always false. Check carefully constants and operators used, these errors might be hard to spot sometimes. In case of complex expression it might help to split it to separate expressions. + + + + Minor + + + + + + + true + false + catchExceptionByValue + Exception Rules + + true + Catch Exception By Value + + The exception is caught by value. It could be caught as a (const) reference which is usually recommended in C++. + + + + Minor + + + + + + + true + false + comparisonFunctionIsAlwaysTrueOrFalse + Conditional Rules + + true + Comparison Function Is Always True Or False + + The function isless is designed to compare two variables. Calling this function with one variable (varName) for both parameters leads to a statement which is always false. + + + + Critical + + + + + + + true + false + CastIntegerToAddressAtReturn + Portability Rules + + true + Cast Integer To Address At Return + + Returning an integer (int/long/etc) in a function with pointer return type is not portable across different platforms and compilers. For example in 32-bit Windows and Linux they are same width, but in 64-bit Windows and Linux they are of different width. In worst case you end up casting 64-bit integer down to 32-bit pointer. The safe way is to always return a pointer. + + + + Minor + + + + + + + true + false + charLiteralWithCharPtrCompare + Simple Type Rules + + true + Char Literal With Char Ptr Compare + + Char literal compared with pointer 'foo'. Did you intend to dereference it? + + + + Critical + + + + + + + true + false + comparisonOfBoolWithBoolError + Simple Type Rules + + true + Comparison Of Bool With Bool Error + + The variable 'var_name' is of type 'bool' and comparing 'bool' value using relational (<, >, <= or >=) operator could cause unexpected results. + + + + Minor + + + + + + + true + false + comparisonOfBoolWithInvalidComparator + Conditional Rules + Simple Type Rules + + true + Comparison Of Bool With Invalid Comparator + + The result of the expression 'expression' is of type 'bool'. Comparing 'bool' value using relational (<, >, <= or >=) operator could cause unexpected results. + + + + Critical + + + + + + + true + false + comparisonOfFuncReturningBoolError + Simple Type Rules + + true + Comparison Of Func Returning Bool Error + + The return type of function 'func_name' is 'bool' and result is of type 'bool'. Comparing 'bool' value using relational (<, >, <= or >=) operator could cause unexpected results. + + + + Minor + + + + + + + true + false + containerOutOfBounds + STL Rules + + true + Container Out Of Bounds + + Out of bounds access in expression 'container[x]' + + + + Blocker + + + + + + + true + false + comparisonOfTwoFuncsReturningBoolError + Simple Type Rules + + true + Comparison Of Two Funcs Returning Bool Error + + The return type of function 'func_name1' and function 'func_name2' is 'bool' and result is of type 'bool'. Comparing 'bool' value using relational (<, >, <= or >=) operator could cause unexpected results. + + + + Minor + + + + + + + true + false + comparePointers + Suspicious Construct Rules + + true + Compare Pointers + + Comparing pointers that point to different objects + + + + Blocker + + + + + + + true + false + constStatement + Suspicious Construct Rules + + true + Const Statement + + Redundant code: Found a statement that begins with type constant. + + + + Critical + + + + + + + true + false + cstyleCast + Readability and Consistency Rules + + true + Cstyle Cast + + C-style pointer casting detected. C++ offers four different kinds of casts as replacements: static_cast, const_cast, dynamic_cast and reinterpret_cast. A C-style cast could evaluate to any of those automatically, thus it is considered safer if the programmer explicitly states which kind of cast is expected. See also: https://www.securecoding.cert.org/confluence/display/cplusplus/EXP05-CPP.+Do+not+use+C-style+casts. + + + + Minor + + + + + + + true + false + commaSeparatedReturn + Readability and Consistency Rules + + true + Comma Separated Return + + Comma is used in return statement. When comma is used in a return statement it can easily be misread as a semicolon. For example in the code below the value of 'b' is returned if the condition is true, but it is easy to think that 'a+1' is returned:\012 if (x)\012 return a + 1,\012 b++;\012However it can be useful to use comma in macros. Cppcheck does not warn when such a macro is then used in a return statement, it is less likely such code is misunderstood. + + + + Minor + + + + + + + true + false + clarifyStatement + Readability and Consistency Rules + + true + Clarify Statement + + A statement like '*A++;' might not do what you intended. Postfix 'operator++' is executed before 'operator*'. Thus, the dereference is meaningless. Did you intend to write '(*A)++;'? + + + + Critical + + + + + + + true + false + constVariable + Readability and Consistency Rules + + true + Const Variable + + Variable 'x' can be declared with const + + + + Minor + + + + + + + true + false + duplicateAssignExpression + Suspicious Construct Rules + + true + Duplicate Assign Expression + + Finding variables 'x' and 'x' that are assigned the same expression is suspicious and might indicate a cut and paste or logic error. Please examine this code carefully to determine if it is correct. + + + + Minor + + + + + + + true + false + deallocret + Memory Handling Rules + + true + Deallocret + + Returning/dereferencing 'p' after it is deallocated / released + + + + Blocker + + + + + + + true + false + duplicateBranch + Suspicious Construct Rules + + true + Duplicate Branch + + Finding the same code in an 'if' and related 'else' branch is suspicious and might indicate a cut and paste or logic error. Please examine this code carefully to determine if it is correct. + + + + Minor + + + + + + + true + false + duplicateBreak + Unreachable Code Rules + + true + Duplicate Break + + Consecutive return, break, continue, goto or throw statements are unnecessary. The second statement can never be executed, and so should be removed. + + + + Minor + + + + + + + true + false + duplicateCondition + Conditional Rules + + true + Duplicate Condition + + The if condition is the same as the previous if condition + + + + Minor + + + + + + + true + false + duplicateConditionalAssign + Conditional Rules + + true + Duplicate Condition and Assignement + + Duplicate expression for the condition and assignment. + + + + Minor + + + + + + + true + false + deallocDealloc + Memory Handling Rules + + true + Dealloc Dealloc + + Deallocating a deallocated pointer: varname + + + + Blocker + + + + + + + true + false + duplicateExpressionTernary + Suspicious Construct Rules + + true + Duplicate Expression Ternary + + Finding the same expression in both branches of ternary operator is suspicious as the same code is executed regardless of the condition. + + + + Minor + + + + + + + true + false + duplicateExpression + Suspicious Construct Rules + + true + Duplicate Expression + + Finding the same expression on both sides of an operator is suspicious and might indicate a cut and paste or logic error. Please examine this code carefully to determine if it is correct. + + + + Minor + + + + + + + true + false + doubleFree + Memory Handling Rules + + true + Double Free + + Memory pointed to by 'varname' is freed twice. + + + + Blocker + + + + + + + true + false + derefInvalidIterator + STL Rules + + true + Deref Invalid Iterator + + Possible dereference of an invalid iterator: i. Make sure to check that the iterator is valid before dereferencing it - not after. + + + + Critical + + + + + + + true + false + duplInheritedMember + Object Orientedness Rules + + true + Dupl Inherited Member + + The class 'class' defines member variable with name 'variable' also defined in its parent class 'class'. + + + + Critical + + + + + + + true + false + danglingLifetime + Memory Handling Rules + + true + Dangling Lifetime + + Non-local variable 'x' will use object. + + + + Blocker + + + + + + + true + false + danglingReference + Memory Handling Rules + + true + Dangling Reference + + Non-local reference variable 'x' to local variable 'y' + + + + Blocker + + + + + + + true + false + divideSizeof + Sizeof Operator Rules + + true + Divide Sizeof + + Division of result of sizeof() on pointer type. sizeof() returns the size of the pointer, not the size of the memory area it points to. + + + + Critical + + + + + + + true + false + danglingTemporaryLifetime + Memory Handling Rules + + true + Dangling Temporary Lifetime + + Using object to temporary. + + + + Blocker + + + + + + + true + false + danglingTempReference + Memory Handling Rules + + true + Dangling Temporary Reference + + Using reference to dangling temporary. + + + + Blocker + + + + + + + true + false + deallocuse + Memory Handling Rules + + true + Deallocuse + + Dereferencing 'varname' after it is deallocated / released + + + + Blocker + + + + + + + true + false + uninitstring + Initialization Rules + + true + Dangerous Use Of Strncpy + + Dangerous usage of 'varname' (strncpy doesn't always null-terminate it). + + + + Blocker + + + + + + + true + false + duplicateValueTernary + Suspicious Construct Rules + + true + Duplicate Value Ternary + + Finding the same value in both branches of ternary operator is suspicious as the same code is executed regardless of the condition. + + + + Minor + + + + + + + true + false + eraseDereference + STL Rules + + true + Erase Dereference + + The iterator 'iter' is invalid before being assigned. Dereferencing or comparing it with another iterator is invalid operation. + + + + Blocker + + + + + + + true + false + exceptDeallocThrow + Exception Rules + + true + Except Dealloc Throw + + Exception thrown in invalid state, 'p' points at deallocated memory. + + + + Critical + + + + + + + true + false + exceptRethrowCopy + Exception Rules + + true + Except Rethrow Copy + + Rethrowing an exception with 'throw varname;' creates an unnecessary copy of 'varname'. To rethrow the caught exception without unnecessary copying or slicing, use a bare 'throw;'. + + + + Minor + + + + + + + true + false + exceptThrowInDestructor + Exception Rules + + true + Except Throw In Destructor + + The class Class is not safe because its destructor throws an exception. If Class is used and an exception is thrown that is caught in an outer scope the program will terminate. + + + + Critical + + + + + + + true + false + funcArgNamesDifferent + Readability and Consistency Rules + + true + Function Argument Names Different + + Function 'function' argument 2 names different: declaration 'A' definition 'B'. + + + + Minor + + + + + + + true + false + funcArgOrderDifferent + Readability and Consistency Rules + + true + Function Argument Order Different + + Function 'function' argument order different: declaration '' definition '' + + + + Critical + + + + + + + true + false + functionConst + Object Orientedness Rules + + true + Function Const + + The member function 'class::function' can be made a const function. Making this function 'const' should not cause compiler errors. Even though the function can be made const function technically it may not make sense conceptually. Think about your design and the task of the function first - is it a function that must not change object internal state? + + + + Minor + + + + + + + true + false + floatConversionOverflow + Simple Type Rules + + true + Float Conversion Overflow + + Undefined behaviour: float (1e+100) to integer conversion overflow. + + + + Blocker + + + + + + + true + false + fflushOnInputStream + Input Output Rules + + true + Fflush On Input Stream + + fflush() called on input stream 'stdin' may result in undefined behaviour on non-linux systems. + + + + Minor + + + + + + + true + false + functionStatic + Object Orientedness Rules + + true + Function Static + + The member function 'class::function' can be made a static function. Making a function static can bring a performance benefit since no 'this' instance is passed to the function. This change should not cause compiler errors but it does not necessarily make sense conceptually. Think about your design and the task of the function first - is it a function that must not access members of class instances? And maybe it is more appropriate to move this function to a unnamed namespace. + + + + Major + + + + + + + true + false + globalLockGuard + Multithreading Rules + + true + Global Lock Guard + + Lock guard is defined globally. Lock guards are intended to be local. A global lock guard could lead to a deadlock since it won't unlock until the end of the program. + + + + Critical + + + + + + + true + false + incompleteArrayFill + Memory Handling Rules + + true + Incomplete Array Fill + + The array 'buffer' is filled incompletely. The function 'memset()' needs the size given in bytes, but an element of the given array is larger than one byte. Did you forget to multiply the size with 'sizeof(*buffer)'? + + + + Critical + + + + + + + true + false + incrementboolean + Simple Type Rules + + true + Increment Boolean + + The operand of a postfix increment operator may be of type bool but it is deprecated by C++ Standard (Annex D-1) and the operand is always set to true. You should assign it the value 'true' instead. + + + + Minor + + + + + + + true + false + invalidContainer + STL Rules + + true + Invalid Container + + Using object that may be invalid. + + + + Blocker + + + + + + + true + false + identicalConditionAfterEarlyExit + Conditional Rules + + true + Identical Condition After Early Exit + + Identical condition 'x', second condition is always false + + + + Critical + + + + + + + true + false + incorrectCharBooleanError + Simple Type Rules + + true + Incorrect Char Boolean Error + + Conversion of char literal 'x' to bool always evaluates to true. + + + + Critical + + + + + + + true + false + invalidContainerLoop + STL Rules + + true + Invalid Container Loop + + Calling 'erase' while iterating the container is invalid. + + + + Blocker + + + + + + + true + false + invalidFree + Memory Handling Rules + + true + Invalid Free + + Mismatching address is freed. The address you get from malloc() must be freed without offset. + + + + Blocker + + + + + + + true + false + invalidFunctionArg + API Rules + + true + Invalid Function Arguments + + Invalid func_name() argument nr 1. The value is 0 or 1 (boolean) but the valid values are '1:4'. + + + + Blocker + + + + + + + true + false + invalidFunctionArgBool + API Rules + + true + Invalid Function Argument Boolean + + Invalid func_name() argument nr 1. A non-boolean value is required. + + + + Blocker + + + + + + + true + false + invalidFunctionArgStr + API Rules + + true + Invalid Function Argument String + + Invalid func_name() argument nr 1. A nul-terminated string is required. + + + + Blocker + + + + + + + true + false + identicalInnerCondition + Conditional Rules + + true + Identical Inner Condition + + Identical inner 'if' condition is always true (outer condition is 'x' and inner condition is 'x'). + + + + Critical + + + + + + + true + false + invalidIterator1 + STL Rules + + true + Invalid Iterator1 + + Invalid iterator: iterator + + + + Blocker + + + + + + + true + false + initializerList + Object Orientedness Rules + + true + Initializer List + + Member variable 'class::variable' is in the wrong place in the initializer list. Members are initialized in the order they are declared, not in the order they are in the initializer list. Keeping the initializer list in the same order that the members were declared prevents order dependent initialization errors. + + + + Minor + + + + + + + true + false + invalidLengthModifierError + API Rules + Input Output Rules + + true + Invalid Length Modifier Error + + 'I' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier. + + + + Critical + + + + + + + true + false + incorrectLogicOperator + Conditional Rules + + true + Incorrect Logic Operator + + Logical disjunction always evaluates to true: foo > 3 && foo < 4. Are these conditions necessary? Did you intend to use && instead? Are the numbers correct? Are you comparing the correct variables? + + + + Critical + + + + + + + true + false + invalidLifetime + Memory Handling Rules + + true + Invalid Lifetime + + Using object that is out of scope. + + + + Blocker + + + + + + + true + false + integerOverflow + Simple Type Rules + + true + Integer Overflow + + Signed integer overflow for expression ''. + + + + Blocker + + + + + + + true + false + IOWithoutPositioning + Input Output Rules + + true + IO Without Positioning + + Read and write operations without a call to a positioning function (fseek, fsetpos or rewind) or fflush in between result in undefined behaviour. + + + + Blocker + + + + + + + true + false + invalidPrintfArgType_float + Input Output Rules + + true + Invalid Printf Arg Type_float + + %f in format string (no. 1) requires 'double' but the argument type is Unknown. + + + + Critical + + + + + + + true + false + invalidPrintfArgType_n + Input Output Rules + + true + Invalid Printf Arg Type_n + + %n in format string (no. 1) requires 'int *' but the argument type is Unknown. + + + + Critical + + + + + + + true + false + invalidPrintfArgType_p + Input Output Rules + + true + Invalid Printf Arg Type_p + + %p in format string (no. 1) requires an address but the argument type is Unknown. + + + + Critical + + + + + + + true + false + invalidPrintfArgType_s + Input Output Rules + + true + Invalid Printf Arg Type_s + + %s in format string (no. 1) requires 'char *' but the argument type is Unknown. + + + + Critical + + + + + + + true + false + invalidPrintfArgType_sint + Input Output Rules + + true + Invalid Printf Arg Type_sint + + %i in format string (no. 1) requires 'int' but the argument type is Unknown. + + + + Critical + + + + + + + true + false + invalidPrintfArgType_uint + Input Output Rules + + true + Invalid Printf Arg Type_uint + + %u in format string (no. 1) requires 'unsigned int' but the argument type is Unknown. + + + + Critical + + + + + + + true + false + invalidPointerCast + Simple Type Rules + + true + Invalid Pointer Cast + + Casting between float * and double * which have an incompatible binary data representation. + + + + Minor + + + + + + + true + false + ignoredReturnValue + Memory Handling Rules + + true + Ignored Return Value + + Return value of function malloc() is not used. + + + + Critical + + + + + + + true + false + invalidscanf + Input Output Rules + + true + Invalid Scanf + + scanf() without field width limits can crash with huge input data. Add a field width specifier to fix this problem.\012\012Sample program that can crash:\012\012#include <stdio.h>\012int main()\012{\012 char c[5];\012 scanf("%s", c);\012 return 0;\012}\012\012Typing in 5 or more characters may make the program crash. The correct usage here is 'scanf("%4s", c);', as the maximum field width does not include the terminating null byte.\012Source: http://linux.die.net/man/3/scanf\012Source: http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/libkern/stdio/scanf.c + + + + Critical + + + + + + + true + false + invalidScanfArgType_float + Input Output Rules + + true + Invalid Scanf Arg Type_float + + %f in format string (no. 1) requires 'float *' but the argument type is Unknown. + + + + Critical + + + + + + + true + false + invalidScanfArgType_int + Input Output Rules + + true + Invalid Scanf Arg Type_int + + %d in format string (no. 1) requires 'int *' but the argument type is Unknown. + + + + Critical + + + + + + + true + false + invalidScanfArgType_s + Input Output Rules + + true + Invalid Scanf Arg Type_s + + %s in format string (no. 1) requires a 'char *' but the argument type is Unknown. + + + + Critical + + + + + + + true + false + incorrectStringBooleanError + Simple Type Rules + + true + Incorrect String Boolean Error + + Conversion of string literal "Hello World" to bool always evaluates to true. + + + + Critical + + + + + + + true + false + incorrectStringCompare + Simple Type Rules + + true + Incorrect String Compare + + String literal "Hello World" doesn't match length argument for substr(). + + + + Critical + + + + + + + true + false + invalidScanfFormatWidth + Input Output Rules + + true + Invalid Scanf Format Width + + Width 5 given in format string (no. 10) is larger than destination buffer '[0]', use %-1s to prevent overflowing it. + + + + Blocker + + + + + + + true + false + invalidScanfFormatWidth_smaller + Input Output Rules + + true + Invalid Smaller Scanf Format Width + + Width -1 given in format string (no. 99) is smaller than destination buffer '[0]'. + + + + Critical + + + + + + + true + false + invalidTestForOverflow + Conditional Rules + + true + Invalid Test For Overflow + + Invalid test for overflow 'x + c < x'; signed integer overflow is undefined behavior. Some mainstream compilers remove such overflow tests when optimising the code and assume it's always false. + + + + Critical + + + + + + + true + false + knownArgument + Suspicious Construct Rules + + true + Known Argument + + Argument 'x-x' to function 'func' is always 0. It does not matter what value 'x' has. + + + + Minor + + + + + + + true + false + knownArgumentHiddenVariableExpression + Suspicious Construct Rules + + true + Known Argument Hidden Variable Expression + + Argument 'x*0' to function 'func' is always 0. Constant literal calculation disable/hide variable expression 'x'. + + + + Minor + + + + + + + true + false + knownEmptyContainer + Suspicious Construct Rules + + true + Known Empty Container + + Iterating over container 'var' that is always empty. + + + + Minor + + + + + + + true + false + localMutex + Multithreading Rules + + true + Local Mutex + + The lock is ineffective because the mutex is locked at the same scope as the mutex itself. + + + + Critical + + + + + + + true + false + leakNoVarFunctionCall + Memory Handling Rules + + true + Leak No Var Function Call + + Allocation with funcName, funcName doesn't release it. + + + + Blocker + + + + + + + true + false + leakReturnValNotUsed + Memory Handling Rules + + true + Leak Return Val Not Used + + Return value of allocation function 'funcName' is not stored. + + + + Blocker + + + + + + + true + false + mismatchAllocDealloc + Memory Handling Rules + + true + Mismatch Alloc Dealloc + + Mismatching allocation and deallocation: varname + + + + Blocker + + + + + + + true + false + moduloAlwaysTrueFalse + Conditional Rules + + true + Modulo Always True False + + Comparison of modulo result is predetermined, because it is always less than 1. + + + + Critical + + + + + + + true + false + mismatchingBitAnd + Conditional Rules + + true + Mismatching Bit And + + Mismatching bitmasks. Result is always 0 (X = Y & 0xf0; Z = X & 0x1; => Z=0). + + + + Minor + + + + + + + true + false + memsetClass + Object Orientedness Rules + + true + Memset Class + + Using 'memfunc' on class that contains a classname is unsafe, because constructor, destructor and copy operator calls are omitted. These are necessary for this non-POD type to ensure that a valid object is created. + + + + Blocker + + + + + + + true + false + mismatchingContainerExpression + Suspicious Construct Rules + + true + Mismatching Container Expression + + Iterators to containers from different expressions 'v1' and 'v2' are used together. + + + + Critical + + + + + + + true + false + memsetClassFloat + Object Orientedness Rules + + true + Memset Class Float + + Using memset() on class which contains a floating point number. This is not portable because memset() sets each byte of a block of memory to a specific value and the actual representation of a floating-point value is implementation defined. Note: In case of an IEEE754-1985 compatible implementation setting all bits to zero results in the value 0.0. + + + + Minor + + + + + + + true + false + mismatchingContainerIterator + STL Rules + + true + Mismatching Container Iterator + + Iterator 'it' from different container 'v1' are used together. + + + + Blocker + + + + + + + true + false + multiCondition + Conditional Rules + + true + Multi Condition + + Expression is always false because 'else if' condition matches previous condition at line 1. + + + + Minor + + + + + + + true + false + memsetClassReference + Object Orientedness Rules + + true + Memset Class Reference + + Using 'memfunc' on class that contains a reference. + + + + Blocker + + + + + + + true + false + memsetFloat + Simple Type Rules + + true + Memset Float + + The 2nd memset() argument 'varname' is a float, its representation is implementation defined. memset() is used to set each byte of a block of memory to a specific value and the actual representation of a floating-point value is implementation defined. + + + + Minor + + + + + + + true + false + memleak + Memory Handling Rules + + true + Memleak + + Memory leak: varname + + + + Blocker + + + + + + + true + false + mismatchingContainers + STL Rules + + true + Mismatching Containers + + Iterators of different containers 'v1' and 'v2' are used together. + + + + Blocker + + + + + + + true + false + missingOverride + Readability and Consistency Rules + + true + Missing Override + + The function '' overrides a function in a base class but is not marked with a 'override' specifier. + + + + Minor + + + + + + + true + false + mallocOnClassError + Object Orientedness Rules + + true + Malloc On Class Error + + Memory for class instance allocated with malloc(), but class a std::string. This is unsafe, since no constructor is called and class members remain uninitialized. Consider using 'new' instead. + + + + Blocker + + + + + + + true + false + mallocOnClassWarning + Object Orientedness Rules + + true + Malloc On Class Warning + + Memory for class instance allocated with malloc(), but class provides constructors. This is unsafe, since no constructor is called and class members remain uninitialized. Consider using 'new' instead. + + + + Critical + + + + + + + true + false + moduloofone + Suspicious Construct Rules + + true + Modulo Of One + + Modulo of one is always equal to zero + + + + Minor + + + + + + + true + false + memleakOnRealloc + Memory Handling Rules + + true + Memleak On Realloc + + Common realloc mistake: 'varname' nulled but not freed upon failure + + + + Blocker + + + + + + + true + false + operatorEqMissingReturnStatement + Object Orientedness Rules + + true + Missing Return From Assignement Operator + + No 'return' statement in non-void function causes undefined behavior. + + + + Blocker + + + + + + + true + false + mismatchSize + Memory Handling Rules + + true + Mismatch Size + + The allocated size sz is not a multiple of the underlying type's size. + + + + Blocker + + + + + + + true + false + multiplySizeof + Sizeof Operator Rules + + true + Multiply Sizeof + + Multiplying sizeof() with sizeof() indicates a logic error. + + + + Critical + + + + + + + true + false + memsetValueOutOfRange + API Rules + + true + Memset Value Out Of Range + + The 2nd memset() argument 'varname' doesn't fit into an 'unsigned char'. The 2nd parameter is passed as an 'int', but the function fills the block of memory using the 'unsigned char' conversion of this value. + + + + Critical + + + + + + + true + false + memsetZeroBytes + API Rules + + true + Memset Zero Bytes + + memset() called to fill 0 bytes. The second and third arguments might be inverted. The function memset ( void * ptr, int value, size_t num ) sets the first num bytes of the block of memory pointed by ptr to the specified value. + + + + Critical + + + + + + + true + false + noOperatorEq + Object Orientedness Rules + + true + No Assignment Operator + + Class 'class' does not have a operator= which is recommended since it has dynamic memory/resource allocation(s). + + + + Critical + + + + + + + true + false + noConstructor + Object Orientedness Rules + + true + No Constructor + + The class 'classname' does not have a constructor although it has private member variables. Member variables of builtin types are left uninitialized when the class is instantiated. That may cause bugs or undefined behavior. + + + + Minor + + + + + + + true + false + noCopyConstructor + Object Orientedness Rules + + true + No Copy Constructor + + Class 'class' does not have a copy constructor which is recommended since it has dynamic memory/resource allocation(s). + + + + Critical + + + + + + + true + false + rethrowNoCurrentException + Suspicious Construct Rules + + true + No Current Exception To Rethrow + + Rethrowing current exception with 'throw;', it seems there is no current exception to rethrow. If there is no current exception this calls std::terminate(). More: https://isocpp.org/wiki/faq/exceptions#throw-without-an-object + + + + Blocker + + + + + + + true + false + negativeContainerIndex + Buffer Overrun Rules + + true + Negative Container Index + + Array index -1 is out of bounds. + + + + Blocker + + + + + + + true + false + noDestructor + Object Orientedness Rules + + true + No Destructor + + Class 'class' does not have a destructor which is recommended since it has dynamic memory/resource allocation(s). + + + + Critical + + + + + + + true + false + noExplicitConstructor + Object Orientedness Rules + + true + No Explicit Constructor + + Class 'classname' has a constructor with 1 argument that is not explicit. Such constructors should in general be explicit for type safety reasons. Using the explicit keyword in the constructor means some mistakes when using the class can be avoided. + + + + Minor + + + + + + + true + false + negativeIndex + Buffer Overrun Rules + + true + Negative Index + + Negative array index + + + + Blocker + + + + + + + true + false + nanInArithmeticExpression + Suspicious Construct Rules + + true + Nan In Arithmetic Expression + + Using NaN/Inf in a computation. Although nothing bad really happens, it is suspicious. + + + + Minor + + + + + + + true + false + nullPointer + Memory Handling Rules + + true + Null Pointer + + Null pointer dereference + + + + Blocker + + + + + + + true + false + nullPointerDefaultArg + Memory Handling Rules + + true + NULL Pointer Dereference With Default Argument + + Possible null pointer dereference if the default parameter value is used: pointer + + + + Critical + + + + + + + true + false + operatorEqRetRefThis + Object Orientedness Rules + + true + Operator Eq Ret Ref This + + 'operator=' should return reference to 'this' instance. + + + + Minor + + + + + + + true + false + operatorEqToSelf + Object Orientedness Rules + + true + Operator Eq To Self + + 'operator=' should check for assignment to self to ensure that each block of dynamically allocated memory is owned and managed by only one instance of the class. + + + + Critical + + + + + + + true + false + operatorEqVarError + Object Orientedness Rules + + true + Operator Eq Var Error + + Member variable 'classname::' is not assigned a value in 'classname::operator='. + + + + Critical + + + + + + + true + false + objectIndex + Memory Handling Rules + + true + Object Index + + The address of local variable '' is accessed at non-zero index. + + + + Blocker + + + + + + + true + false + oppositeInnerCondition + Conditional Rules + + true + Opposite Inner Condition + + Opposite inner 'if' condition leads to a dead code block (outer condition is 'x' and inner condition is '!x'). + + + + Critical + + + + + + + true + false + oppositeExpression + Suspicious Construct Rules + + true + Opposite Expression + + Finding the opposite expression on both sides of an operator is suspicious and might indicate a cut and paste or logic error. Please examine this code carefully to determine if it is correct. + + + + Minor + + + + + + + true + false + overlappingStrcmp + Suspicious Construct Rules + + true + Overlapping Strcmp + + The expression 'strcmp(x,"def") != 0' is suspicious. It overlaps 'strcmp(x,"abc") == 0'. + + + + Critical + + + + + + + true + false + pointerArithBool + Simple Type Rules + + true + Pointer Arith Bool + + Converting pointer arithmetic result to bool. The boolean result is always true unless there is pointer arithmetic overflow, and overflow is undefined behaviour. Probably a dereference is forgotten. + + + + Blocker + + + + + + + true + false + publicAllocationError + Memory Handling Rules + + true + Public Allocation Error + + Possible leak in public function. The pointer 'varname' is not deallocated before it is allocated. + + + + Critical + + + + + + + true + false + pointerAdditionResultNotNull + Conditional Rules + + true + Pointer Addition Null Check + + Comparison is wrong. Result of 'ptr+1' can't be 0 unless there is pointer overflow, and pointer overflow is undefined behaviour. + + + + Critical + + + + + + + true + false + nullPointerArithmeticRedundantCheck + Memory Handling Rules + + true + Pointer Arithmetic Or Redundant Check With NULL + + Either the condition is redundant or there is pointer arithmetic with NULL pointer. + + + + Critical + + + + + + + true + false + nullPointerArithmetic + Memory Handling Rules + + true + Pointer Arithmetic With NULL + + Pointer arithmetic with NULL pointer. + + + + Blocker + + + + + + + true + false + passedByValue + Performance Rules + + true + Passed By Value + + Parameter 'parametername' is passed by value. It could be passed as a const reference which is usually faster and recommended in C++. + + + + Major + + + + + + + false + false + preprocessorErrorDirective + Preprocessor Rules + + true + Preprocessor Error Directive + + #error message + + + + Blocker + + + + + + + true + false + pointerLessThanZero + Simple Type Rules + + true + Pointer Less Than Zero + + A pointer can not be negative so it is either pointless or an error to check if it is. + + + + Minor + + + + + + + true + false + postfixOperator + Performance Rules + + true + Postfix Operator + + Prefix ++/-- operators should be preferred for non-primitive types. Pre-increment/decrement can be more efficient than post-increment/decrement. Post-increment/decrement usually involves keeping a copy of the previous value around and adds a little extra code. + + + + Major + + + + + + + true + false + pointerOutOfBounds + Buffer Overrun Rules + + true + Pointer Out Of Bounds + + Pointer arithmetic overflow. + + + + Minor + + + + + + + true + false + pointerPositive + Simple Type Rules + + true + Pointer Positive + + A pointer can not be negative so it is either pointless or an error to check if it is not. + + + + Minor + + + + + + + true + false + pointerSize + Sizeof Operator Rules + + true + Pointer Size + + Size of pointer 'varname' used instead of size of its data. This is likely to lead to a buffer overflow. You probably intend to write 'sizeof(*varname)'. + + + + Critical + + + + + + + true + false + pureVirtualCall + Object Orientedness Rules + + true + Pure Virtual Call + + Call of pure virtual function 'f' in constructor. The call will fail during runtime. + + + + Critical + + + + + + + true + false + redundantAssignment + Performance Rules + + true + Redundant Assignment + + Variable 'var' is reassigned a value before the old one has been used. + + + + Minor + + + + + + + true + false + raceAfterInterlockedDecrement + Multithreading Rules + + true + Race After Interlocked Decrement + + Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead. + + + + Blocker + + + + + + + true + false + redundantAssignInSwitch + Suspicious Construct Rules + + true + Redundant Assign In Switch + + Variable 'var' is reassigned a value before the old one has been used. 'break;' missing? + + + + Minor + + + + + + + true + false + returnAddressOfAutoVariable + Memory Handling Rules + + true + Return Address Of Auto Variable + + Address of an auto-variable returned. + + + + Blocker + + + + + + + true + false + returnAddressOfFunctionParameter + Memory Handling Rules + + true + Return Address Of Function Parameter + + Address of the function parameter 'parameter' becomes invalid after the function exits because function parameters are stored on the stack which is freed when the function exits. Thus the returned value is invalid. + + + + Blocker + + + + + + + true + false + redundantBitwiseOperationInSwitch + Suspicious Construct Rules + + true + Redundant Bitwise Operation In Switch + + Redundant bitwise operation on 'varname' in 'switch' statement. 'break;' missing? + + + + Minor + + + + + + + true + false + redundantCopyInSwitch + Suspicious Construct Rules + + true + Redundant Copy In Switch + + Buffer 'var' is being written before its old content has been used. 'break;' missing? + + + + Minor + + + + + + + true + false + redundantCopyLocalConst + Performance Rules + + true + Redundant Copy Local Const + + The const variable 'varname' is assigned a copy of the data. You can avoid the unnecessary data copying by converting 'varname' to const reference. + + + + Major + + + + + + + true + false + redundantCondition + Conditional Rules + + true + Redundant Condition + + Redundant condition: If x > 11 the condition x > 10 is always true. + + + + Minor + + + + + + + true + false + redundantCopy + Performance Rules + + true + Redundant Copy + + Buffer 'var' is being written before its old content has been used. + + + + Major + + + + + + + true + false + returnDanglingLifetime + Memory Handling Rules + + true + Return Dangling Lifetime + + Returning object that will be invalid when returning. + + + + Blocker + + + + + + + true + false + reademptycontainer + STL Rules + + true + Read Empty Container + + Reading from empty STL container 'var' + + + + Minor + + + + + + + true + false + returnReference + Memory Handling Rules + + true + Return Reference + + Reference to local variable returned. + + + + Blocker + + + + + + + true + false + redundantInitialization + Initialization Rules + + true + Redundant Initialization + + Redundant initialization for 'var'. The initialized value is overwritten before it is read. + + + + Minor + + + + + + + true + false + redundantIfRemove + STL Rules + + true + Redundant If Remove + + Redundant checking of STL container element existence before removing it. It is safe to call the remove method on a non-existing element. + + + + Minor + + + + + + + true + false + resourceLeak + Memory Handling Rules + + true + Resource Leak + + Resource leak: varname + + + + Blocker + + + + + + + true + false + returnLocalVariable + Memory Handling Rules + + true + Return Local Variable + + Pointer to local array variable returned. + + + + Blocker + + + + + + + true + false + returnNonBoolInBooleanFunction + Suspicious Construct Rules + + true + Return Address Of Auto Variable + + Non-boolean value returned from function returning bool + + + + Minor + + + + + + + true + false + nullPointerRedundantCheck + Memory Handling Rules + + true + Redundant NULL Pointer Check + + Either the condition is redundant or there is possible null pointer dereference: pointer. + + + + Critical + + + + + + + true + false + redundantPointerOp + Suspicious Construct Rules + + true + Redundant Pointer Operation + + Redundant pointer operation on 'varname' - it's already a pointer. + + + + Minor + + + + + + + true + false + returnTempReference + Memory Handling Rules + + true + Return Temp Reference + + Reference to temporary returned. + + + + Blocker + + + + + + + true + false + readWriteOnlyFile + Input Output Rules + + true + Read Write Only File + + Read operation on a file that was opened only for writing. + + + + Blocker + + + + + + + true + false + selfAssignment + Suspicious Construct Rules + + true + Self Assignment + + Redundant assignment of 'varname' to itself. + + + + Critical + + + + + + + true + false + shadowArgument + Readability and Consistency Rules + + true + Shadow Argument + + Local variable 'argument' shadows outer argument + + + + Minor + + + + + + + true + false + shiftNegative + Simple Type Rules + + true + Shift By Negative + + Shifting by a negative value is undefined behaviour + + + + Blocker + + + + + + + true + false + signConversion + Simple Type Rules + + true + Sign Conversion + + Expression 'var' can have a negative value. That is converted to an unsigned value and used in an unsigned calculation. + + + + Critical + + + + + + + true + false + signedCharArrayIndex + Simple Type Rules + + true + Signed Char Array Index + + Signed 'char' type used as array index. If the value can be greater than 127 there will be a buffer underflow because of sign extension. + + + + Critical + + + + + + + true + false + stlcstrParam + STL Rules + + true + Stlcstr Param + + The conversion from const char* as returned by c_str() to std::string creates an unnecessary string copy. Solve that by directly passing the string. + + + + Major + + + + + + + true + false + stlcstrReturn + STL Rules + + true + Stlcstr Return + + The conversion from const char* as returned by c_str() to std::string creates an unnecessary string copy. Solve that by directly returning the string. + + + + Major + + + + + + + true + false + stlcstrthrow + STL Rules + + true + Stlcstr Throw + + Dangerous usage of c_str(). The string is destroyed after the c_str() call so the thrown pointer is invalid. + + + + Blocker + + + + + + + true + false + shadowFunction + Readability and Consistency Rules + + true + Shadow Function + + Local variable 'function' shadows outer function + + + + Minor + + + + + + + true + false + selfInitialization + Object Orientedness Rules + + true + Self Initialization + + Member variable 'var' is initialized by itself. + + + + Blocker + + + + + + + true + false + sameIteratorExpression + Performance Rules + + true + Same Iterator Expression + + Same iterators expression are used for algorithm. + + + + Minor + + + + + + + true + false + iterators1 + STL Rules + + true + Same Iterator With Different Containers1 + + Same iterator is used with different containers 'container1' and 'container2'. + + + + Blocker + + + + + + + true + false + iterators2 + STL Rules + + true + Same Iterator With Different Containers2 + + Same iterator is used with different containers 'container0' and 'container1'. + + + + Blocker + + + + + + + true + false + iterators3 + STL Rules + + true + Same Iterator With Different Containers3 + + Same iterator is used with containers 'container' that are defined in different scopes. + + + + Blocker + + + + + + + true + false + stringLiteralWrite + Simple Type Rules + + true + String Literal Write + + Modifying string literal directly or indirectly is undefined behaviour. + + + + Blocker + + + + + + + true + false + shiftNegativeLHS + Simple Type Rules + + true + Shift Negative + + Shifting a negative value is technically undefined behaviour + + + + Minor + + + + + + + true + false + seekOnAppendedFile + Input Output Rules + + true + Seek On Appended File + + Repositioning operation performed on a file opened in append mode has no effect. + + + + Critical + + + + + + + true + false + sizeofCalculation + Sizeof Operator Rules + + true + Sizeof Calculation + + Found calculation inside sizeof(). + + + + Critical + + + + + + + true + false + sprintfOverlappingData + Simple Type Rules + + true + Sprintf Overlapping Data + + The variable 'varname' is used both as a parameter and as destination in s[n]printf(). The origin and destination buffers overlap. Quote from glibc (C-library) documentation (http://www.gnu.org/software/libc/manual/html_mono/libc.html#Formatted-Output-Functions): "If copying takes place between objects that overlap as a result of a call to sprintf() or snprintf(), the results are undefined." + + + + Blocker + + + + + + + true + false + sizeofDivisionMemfunc + Sizeof Operator Rules + + true + Sizeof Division Memfunc + + Division by result of sizeof(). memset() expects a size in bytes, did you intend to multiply instead? + + + + Critical + + + + + + + true + false + sizeofDereferencedVoidPointer + Sizeof Operator Rules + + true + Sizeof Dereferenced Void Pointer + + '*varname' is of type 'void', the behaviour of 'sizeof(void)' is not covered by the ISO C standard. A value for 'sizeof(void)' is defined only as part of a GNU C extension, which defines 'sizeof(void)' to be 1. + + + + Minor + + + + + + + true + false + sizeofFunctionCall + Sizeof Operator Rules + + true + Sizeof Function Call + + Found function call inside sizeof(). + + + + Critical + + + + + + + true + false + sizeofsizeof + Sizeof Operator Rules + + true + Sizeof Sizeof + + Calling sizeof for 'sizeof looks like a suspicious code and most likely there should be just one 'sizeof'. The current code is equivalent to 'sizeof(size_t)' + + + + Critical + + + + + + + true + false + sizeofVoid + Sizeof Operator Rules + + true + Sizeof Void + + Behaviour of 'sizeof(void)' is not covered by the ISO C standard. A value for 'sizeof(void)' is defined only as part of a GNU C extension, which defines 'sizeof(void)' to be 1. + + + + Minor + + + + + + + true + false + sizeofwithnumericparameter + Sizeof Operator Rules + + true + Sizeof With Numeric Parameter + + It is unusual to use a constant value with sizeof. For example, 'sizeof(10)' returns 4 (in 32-bit systems) or 8 (in 64-bit systems) instead of 10. 'sizeof('A')' and 'sizeof(char)' can return different results. + + + + Critical + + + + + + + true + false + sizeofwithsilentarraypointer + Sizeof Operator Rules + + true + Sizeof With Silent Array Pointer + + Using 'sizeof' for array given as function argument returns the size of a pointer. It does not return the size of the whole array in bytes as might be expected. For example, this code:\012 int f(char a[100]) {\012 return sizeof(a);\012 }\012returns 4 (in 32-bit systems) or 8 (in 64-bit systems) instead of 100 (the size of the array in bytes). + + + + Critical + + + + + + + true + false + strPlusChar + Simple Type Rules + + true + Str Plus Char + + Unusual pointer arithmetic. A value of type 'char' is added to a string literal. + + + + Blocker + + + + + + + true + false + suspiciousSemicolon + Readability and Consistency Rules + + true + Suspicious Semicolon + + Suspicious use of ; at the end of '' statement. + + + + Critical + + + + + + + true + false + staticStringCompare + Simple Type Rules + + true + Static String Compare + + The compared strings, 'str1' and 'str2', are always unequal. Therefore the comparison is unnecessary and looks suspicious. + + + + Critical + + + + + + + true + false + stlBoundaries + STL Rules + + true + Stl Boundaries + + Iterator compared with operator<. This is dangerous since the order of items in the container is not guaranteed. One should use operator!= instead to compare iterators. + + + + Blocker + + + + + + + true + false + stlcstr + STL Rules + + true + Stlcstr + + Dangerous usage of c_str(). The c_str() return value is only valid until its string is deleted. + + + + Blocker + + + + + + + true + false + stlFindInsert + STL Rules + + true + Stl Find Before Insert + + Searching before insertion is not necessary. + + + + Major + + + + + + + true + false + stlIfFind + STL Rules + + true + Stl If Find + + Suspicious condition. The result of find() is an iterator, but it is not properly checked. + + + + Critical + + + + + + + true + false + stlIfStrFind + STL Rules + + true + Stl If Str Find + + Either inefficient or wrong usage of string::find(). string::starts_with() will be faster if string::find's result is compared with 0, because it will not scan the whole string. If your intention is to check that there are no findings in the string, you should compare with std::string::npos. + + + + Major + + + + + + + true + false + StlMissingComparison + STL Rules + + true + Stl Missing Comparison + + The iterator incrementing is suspicious - it is incremented at line and then at line . The loop might unintentionally skip an element in the container. There is no comparison between these increments to prevent that the iterator is incremented beyond the end. + + + + Critical + + + + + + + true + false + stlOutOfBounds + STL Rules + + true + Stl Out Of Bounds + + When i==foo.size(), foo[i] is out of bounds. + + + + Blocker + + + + + + + true + false + stlSize + STL Rules + + true + Stl Size + + Checking for 'list' emptiness might be inefficient. Using list.empty() instead of list.size() can be faster. list.size() can take linear time but list.empty() is guaranteed to take constant time. + + + + Major + + + + + + + true + false + shiftTooManyBits + Simple Type Rules + + true + Shift Too Many Bits + + Shifting 32-bit value by 40 bits is undefined behaviour + + + + Blocker + + + + + + + true + false + shiftTooManyBitsSigned + Simple Type Rules + + true + Shift Too Many Bits Signed + + Shifting signed 32-bit value by 31 bits is implementation-defined behaviour + + + + Blocker + + + + + + + true + false + stringCompare + Simple Type Rules + + true + String Compare + + The compared strings, 'varname1' and 'varname2', are identical. This could be a logic bug. + + + + Critical + + + + + + + true + false + suspiciousCase + Suspicious Construct Rules + + true + Suspicious Case + + Using an operator like '||' in a case label is suspicious. Did you intend to use a bitwise operator, multiple case labels or if/else instead? + + + + Critical + + + + + + + true + false + shadowVariable + Readability and Consistency Rules + + true + Shadow Variable + + Local variable 'variable' shadows outer variable + + + + Minor + + + + + + + true + false + throwInNoexceptFunction + Exception Rules + + true + Throw In Noexcept Function + + Exception thrown in function declared not to throw exceptions. + + + + Blocker + + + + + + + true + false + truncLongCastAssignment + Simple Type Rules + + true + Trunc Long Cast Assignment + + int result is assigned to long variable. If the variable is long to avoid loss of information, then there is loss of information. To avoid loss of information you must cast a calculation operand to long, for example 'l = a * b;' => 'l = (long)a * b;'. + + + + Minor + + + + + + + true + false + truncLongCastReturn + Simple Type Rules + + true + Trunc Long Cast Return + + int result is returned as long value. If the return value is long to avoid loss of information, then there is loss of information. To avoid loss of information you must cast a calculation operand to long, for example 'return a*b;' => 'return (long)a*b'. + + + + Minor + + + + + + + true + false + thisSubtraction + Object Orientedness Rules + + true + This Subtraction + + Suspicious pointer subtraction. Did you intend to write '->'? + + + + Critical + + + + + + + true + false + thisUseAfterFree + Memory Handling Rules + + true + This Is Used After Free + + Using member 'x' when 'this' might be invalid + + + + Critical + + + + + + + true + false + leakUnsafeArgAlloc + Memory Handling Rules + + true + Unsafe allocation + + Unsafe allocation. If funcName() throws, memory could be leaked. Use make_shared<int>() instead. + + + + Critical + + + + + + + true + false + uselessAssignmentArg + Memory Handling Rules + + true + Useless Assignment Arg + + Assignment of function parameter has no effect outside the function. + + + + Minor + + + + + + + true + false + uselessAssignmentPtrArg + Memory Handling Rules + + true + Useless Assignment Ptr Arg + + Assignment of function parameter has no effect outside the function. Did you forget dereferencing it? + + + + Critical + + + + + + + true + false + unassignedVariable + Unnecessary and Unused Code Rules + + true + Unassigned Variable + + Variable 'varname' is not assigned a value. + + + + Minor + + + + + + + true + false + uselessCallsCompare + STL Rules + + true + Useless Calls Compare + + 'std::string::find()' returns zero when given itself as parameter (str.find(str)). As it is currently the code is inefficient. It is possible either the string searched ('str') or searched for ('str') is wrong. + + + + Critical + + + + + + + true + false + unsafeClassCanLeak + Memory Handling Rules + + true + Unsafe Class Can Leak + + The class 'class' is unsafe, wrong usage can cause memory/resource leaks for 'class::varname'. This can for instance be fixed by adding proper cleanup in the destructor. + + + + Minor + + + + + + + true + false + uselessCallsEmpty + STL Rules + + true + Useless Calls Empty + + Ineffective call of function 'empty()'. Did you intend to call 'clear()' instead? + + + + Critical + + + + + + + true + false + useClosedFile + Input Output Rules + + true + Use Closed File + + Used file that is not opened. + + + + Blocker + + + + + + + true + false + uselessCallsRemove + STL Rules + + true + Useless Calls Remove + + The return value of std::remove() is ignored. This function returns an iterator to the end of the range containing those elements that should be kept. Elements past new end remain valid but with unspecified values. Use the erase method of the container to delete them. + + + + Critical + + + + + + + true + false + unsafeClassRefMember + Initialization Rules + + true + Unsafe Class Reference Member + + Unsafe class checking: The const reference member 'UnsafeClass::var' is initialized by a const reference constructor argument. You need to be careful about lifetime issues. If you pass a local variable or temporary value in this constructor argument, be extra careful. If the argument is always some global object that is never destroyed then this is safe usage. However it would be defensive to make the member 'UnsafeClass::var' a non-reference variable or a smart pointer. + + + + Critical + + + + + + + true + false + uselessCallsSwap + STL Rules + + true + Useless Calls Swap + + The 'swap()' function has no logical effect when given itself as parameter (str.swap(str)). As it is currently the code is inefficient. Is the object or the parameter wrong here? + + + + Major + + + + + + + true + false + uselessCallsSubstr + STL Rules + + true + Useless Calls Substr + + Ineffective call of function 'substr' because it returns a copy of the object. Use operator= instead. + + + + Major + + + + + + + true + false + uninitDerivedMemberVar + Initialization Rules + + true + Uninitialized Derived Member Variable + + Member variable 'classname::varname' is not initialized in the constructor. Maybe it should be initialized directly in the class classname? + + + + Critical + + + + + + + true + false + uninitDerivedMemberVarPrivate + Initialization Rules + + true + Uninitialized Derived Private Member Variable + + Member variable 'classname::varnamepriv' is not initialized in the constructor. Maybe it should be initialized directly in the class classname? + + + + Critical + + + + + + + true + false + unknownEvaluationOrder + Side Effect Rules + + true + Unknown Evaluation Order + + Expression 'x = x++;' depends on order of evaluation of side effects + + + + Blocker + + + + + + + true + false + unhandledExceptionSpecification + Exception Rules + + true + Unhandled Exception Specification + + Unhandled exception specification when calling function foo(). Either use a try/catch around the function call, or add a exception specification for funcname() also. + + + + Minor + + + + + + + true + false + uninitdata + Initialization Rules + + true + Uninitialized Data + + Memory is allocated but not initialized: varname + + + + Blocker + + + + + + + true + false + useInitializationList + Object Orientedness Rules + + true + Use Initialization List + + When an object of a class is created, the constructors of all member variables are called consecutively in the order the variables are declared, even if you don't explicitly write them to the initialization list. You could avoid assigning 'variable' a value by passing the value to the constructor in the initialization list. + + + + Major + + + + + + + true + false + uninitStructMember + Initialization Rules + + true + Uninit Struct Member + + Uninitialized struct member: a.b + + + + Blocker + + + + + + + true + false + uninitvar + Initialization Rules + + true + Uninitialized Variable + + Uninitialized variable: varname + + + + Blocker + + + + + + + true + false + unusedLabel + Unnecessary and Unused Code Rules + + true + Unused Label + + Label '' is not used. + + + + Minor + + + + + + + true + false + unusedLabelConfiguration + Unnecessary and Unused Code Rules + + true + Unused Label In This Configuration + + Label '' is not used. There is #if in function body so the label might be used in code that is removed by the preprocessor. + + + + Minor + + + + + + + true + false + unsignedLessThanZero + Simple Type Rules + + true + Unsigned Less Than Zero + + The unsigned expression 'varname' will never be negative so it is either pointless or an error to check if it is. + + + + Minor + + + + + + + true + false + uninitMemberVar + Object Orientedness Rules + + true + Uninitialized Member Variable + + Member variable 'classname::varname' is not initialized in the constructor. + + + + Critical + + + + + + + true + false + unsignedPositive + Simple Type Rules + + true + Unsigned Positive + + Unsigned expression 'varname' can't be negative so it is unnecessary to test it. + + + + Minor + + + + + + + true + false + unusedPrivateFunction + Object Orientedness Rules + + true + Unused Private Function + + Unused private function: 'classname::funcname' + + + + Minor + + + + + + + true + false + unpreciseMathCall + API Rules + + true + Unprecise Math Call + + Expression '1 - erf(x)' can be replaced by 'erfc(x)' to avoid loss of precision. + + + + Minor + + + + + + + true + false + uninitMemberVarPrivate + Initialization Rules + + true + Uninitialized Private Member Variable + + Member variable 'classname::varnamepriv' is not initialized in the constructor. + + + + Critical + + + + + + + true + false + unreachableCode + Unreachable Code Rules + + true + Unreachable Code + + Statements following return, break, continue, goto or throw will never be executed. + + + + Minor + + + + + + + true + false + unreadVariable + Unnecessary and Unused Code Rules + + true + Unread Variable + + Variable 'varname' is assigned a value that is never used. + + + + Minor + + + + + + + true + false + useStlAlgorithm + STL Rules + + true + Use STL Algorithm + + Consider using algorithm instead of a raw loop. + + + + Minor + + + + + + + true + false + unusedLabelSwitch + Unnecessary and Unused Code Rules + + true + Unused Switch Label + + Label '' is not used. Should this be a 'case' of the enclosing switch()? + + + + Critical + + + + + + + true + false + unusedLabelSwitchConfiguration + Unnecessary and Unused Code Rules + + true + Unused Switch Label in This Configuration + + Label '' is not used. There is #if in function body so the label might be used in code that is removed by the preprocessor. Should this be a 'case' of the enclosing switch()? + + + + Critical + + + + + + + true + false + unusedAllocatedMemory + Unnecessary and Unused Code Rules + + true + Unused Allocated Memory + + Variable 'varname' is allocated memory that is never used. + + + + Minor + + + + + + + true + false + unusedFunction + Unnecessary and Unused Code Rules + + true + Unused Function + + The function 'funcName' is never used. + + + + Minor + + + + + + + true + false + unusedStructMember + Unnecessary and Unused Code Rules + + true + Unused Struct Member + + struct member 'structname::variable' is never used. + + + + Minor + + + + + + + true + false + unusedScopedObject + Suspicious Construct Rules + + true + Unused Scoped Object + + Instance of 'varname' object is destroyed immediately. + + + + Minor + + + + + + + true + false + unusedVariable + Unnecessary and Unused Code Rules + + true + Unused Variable + + Unused variable: varname + + + + Minor + + + + + + + true + false + va_end_missing + Variable Argument Related Rules + + true + Va_end Missing + + va_list 'vl' was opened but not closed by va_end(). + + + + Blocker + + + + + + + true + false + va_list_usedBeforeStarted + Variable Argument Related Rules + + true + Va_list Used Before Started + + va_list 'vl' used before va_start() was called. + + + + Blocker + + + + + + + true + false + va_start_referencePassed + Variable Argument Related Rules + + true + Va_start Reference Passed + + Using reference 'arg1' as parameter for va_start() results in undefined behaviour. + + + + Blocker + + + + + + + true + false + va_start_subsequentCalls + Variable Argument Related Rules + + true + Va_start Subsequent Calls + + va_start() or va_copy() called subsequently on 'vl' without va_end() in between. + + + + Blocker + + + + + + + true + false + va_start_wrongParameter + Variable Argument Related Rules + + true + Va_start Wrong Parameter + + 'arg1' given to va_start() is not last named argument of the function. Did you intend to pass 'arg2'? + + + + Critical + + + + + + + true + false + virtualCallInConstructor + Object Orientedness Rules + + true + Virtual Call In Constructor + + Virtual function 'f' is called from constructor '' at line 1. Dynamic binding is not used. + + + + Minor + + + + + + + true + false + literalWithCharPtrCompare + Simple Type Rules + + true + Variable Comparison With String Literal + + String literal compared with variable 'foo'. Did you intend to use strcmp() instead? + + + + Critical + + + + + + + true + false + virtualDestructor + Object Orientedness Rules + + true + Virtual Destructor + + Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. If you destroy instances of the derived class by deleting a pointer that points to the base class, only the destructor of the base class is executed. Thus, dynamic memory that is managed by the derived class could leak. This can be avoided by adding a virtual destructor to the base class. + + + + Blocker + + + + + + + true + false + varFuncNullUB + Variable Argument Related Rules + + true + Var Func Null UB + + Passing NULL after the last typed argument to a variadic function leads to undefined behaviour.\012The C99 standard, in section 7.15.1.1, states that if the type used by va_arg() is not compatible with the type of the actual next argument (as promoted according to the default argument promotions), the behavior is undefined.\012The value of the NULL macro is an implementation-defined null pointer constant (7.17), which can be any integer constant expression with the value 0, or such an expression casted to (void*) (6.3.2.3). This includes values like 0, 0L, or even 0LL.\012In practice on common architectures, this will cause real crashes if sizeof(int) != sizeof(void*), and NULL is defined to 0 or any other null pointer constant that promotes to int.\012To reproduce you might be able to use this little code example on 64bit platforms. If the output includes "ERROR", the sentinel had only 4 out of 8 bytes initialized to zero and was not detected as the final argument to stop argument processing via va_arg(). Changing the 0 to (void*)0 or 0L will make the "ERROR" output go away.\012#include <stdarg.h>\012#include <stdio.h>\012\012void f(char *s, ...) {\012 va_list ap;\012 va_start(ap,s);\012 for (;;) {\012 char *p = va_arg(ap,char*);\012 printf("%018p, %s\n", p, (long)p & 255 ? p : "");\012 if(!p) break;\012 }\012 va_end(ap);\012}\012\012void g() {\012 char *s2 = "x";\012 char *s3 = "ERROR";\012\012 // changing 0 to 0L for the 7th argument (which is intended to act as sentinel) makes the error go away on x86_64\012 f("first", s2, s2, s2, s2, s2, 0, s3, (char*)0);\012}\012\012void h() {\012 int i;\012 volatile unsigned char a[1000];\012 for (i = 0; i<sizeof(a); i++)\012 a[i] = -1;\012}\012\012int main() {\012 h();\012 g();\012 return 0;\012} + + + + Minor + + + + + + + true + false + variableScope + Readability and Consistency Rules + + true + Variable Scope + + The scope of the variable 'varname' can be reduced. Warning: Be careful when fixing this message, especially when there are inner loops. Here is an example where cppcheck will write that the scope for 'i' can be reduced:\012void f(int x)\012{\012 int i = 0;\012 if (x) {\012 // it's safe to move 'int i = 0;' here\012 for (int n = 0; n < 10; ++n) {\012 // it is possible but not safe to move 'int i = 0;' here\012 do_something(&i);\012 }\012 }\012}\012When you see this message it is always safe to reduce the variable scope 1 level. + + + + Minor + + + + + + + true + false + wrongmathcall + API Rules + + true + Wrong Math Call + + Passing value '#' to #() leads to implementation-defined result. + + + + Critical + + + + + + + true + false + wrongPipeParameterSize + API Rules + + true + Wrong Pipe Parameter Size + + The pipe()/pipe2() system command takes an argument, which is an array of exactly two integers.\012The variable 'varname' is an array of size dimension, which does not match. + + + + Blocker + + + + + + + true + false + wrongPrintfScanfArgNum + Input Output Rules + + true + Wrong Printf Scanf Arg Num + + printf format string requires 3 parameters but only 2 are given. + + + + Blocker + + + + + + + true + false + wrongPrintfScanfParameterPositionError + Input Output Rules + + true + Wrong Printf Scanf Parameter Position Error + + printf: referencing parameter 2 while 1 arguments given + + + + Critical + + + + + + + true + false + writeReadOnlyFile + Input Output Rules + + true + Write Read Only File + + Write operation on a file that was opened only for reading. + + + + Blocker + + + + + + + true + false + zerodiv + Division Rules + + true + Zerodiv + + Division by zero. + + + + Blocker + + + + + + + true + false + zerodivcond + Division Rules + + true + Zerodivcond + + Either the condition is redundant or there is division by zero. + + + + Blocker + + + + + + + true + true + summarized + + true + Conditional Rules + The Conditional Ruleset contains rules that find condition mistakes. + The Conditional Ruleset contains rules that find condition mistakes. + + + + + + + + + true + true + summarized + + true + Division Rules + The Division Ruleset contains rules about the division operator. + The Division Ruleset contains rules about the division operator. + + + + + + + + + true + true + summarized + + true + Exception Rules + The Exception Ruleset contains rules about throwing and catching exceptions. + The Exception Ruleset contains rules about throwing and catching exceptions. + + + + + + + + + true + true + summarized + + true + Initialization Rules + The Initialization Ruleset contains rules about the initialization of allocated memory, variables and members. + The Initialization Ruleset contains rules about the initialization of allocated memory, variables and members. + + + + + + + + + true + true + summarized + + true + Input Output Rules + The Input Output Ruleset contains rules for input output operations. + The Input Output Ruleset contains rules for input output operations. + + + + + + + + + true + true + summarized + + true + Memory Handling Rules + The Memory Handling Ruleset contains rules about memory leaks and common memory management problems. + The Memory Handling Ruleset contains rules about memory leaks and common memory management problems. + + + + + + + + + true + true + summarized + + true + Multithreading Rules + Rules that flag issues when dealing with multiple threads of execution. + Rules that flag issues when dealing with multiple threads of execution. + + + + + + + + + true + true + summarized + + true + Object Orientedness Rules + The Object Orientedness Ruleset contains rules that find various mistakes about classes and other object orientedness related constructs. + The Object Orientedness Ruleset contains rules that find various mistakes about classes and other object orientedness related constructs. + + + + + + + + + true + true + summarized + + true + Performance Rules + The Performance Ruleset contains rules that find various performance issues. + The Performance Ruleset contains rules that find various performance issues. + + + + + + + + + true + true + summarized + + true + Portability Rules + The Portability Ruleset contains rules that find portability issues. + The Portability Ruleset contains rules that find portability issues. + + + + + + + + + true + true + summarized + + true + Preprocessor Rules + The Preprocessor Ruleset contains rules about preprocessor definitions. + The Preprocessor Ruleset contains rules about preprocessor definitions. + + + + + + + + + true + true + summarized + + true + Readability and Consistency Rules + The Readability and Consistency Ruleset contains rules about constructs that reduce the code readability. + The Readability and Consistency Ruleset contains rules about constructs that reduce the code readability. + + + + + + + + + true + true + summarized + + true + STL Rules + The STL Ruleset contains rules that find mistakes of STL usage (invalidation of iterators, mismatching containers, etc). + The STL Ruleset contains rules that find mistakes of STL usage (invalidation of iterators, mismatching containers, etc). + + + + + + + + + true + true + summarized + + true + Side Effect Rules + The Side Effect Ruleset contains rules that find suspicious constructs that can have side effects. + The Side Effect Ruleset contains rules that find suspicious constructs that can have side effects. + + + + + + + + + true + true + summarized + + true + Simple Type Rules + The Simple Type Ruleset contains rules that find simple type related issues. + The Simple Type Ruleset contains rules that find simple type related issues. + + + + + + + + + true + true + summarized + + true + Sizeof Operator Rules + The Sizeof Operator Ruleset contains rules that check usage of sizeof operator. + The Sizeof Operator Ruleset contains rules that check usage of sizeof operator. + + + + + + + + + true + true + summarized + + true + Suspicious Construct Rules + The Suspicious Construct Ruleset contains rules about constructs that are redundant or could lead to unexpected results. + The Suspicious Construct Ruleset contains rules about constructs that are redundant or could lead to unexpected results. + + + + + + + + + true + true + summarized + + true + Unnecessary and Unused Code Rules + The Unnecessary and Unused Code Ruleset contains a collection of rules for unnecessary,unused or ineffective code. + The Unnecessary and Unused Code Ruleset contains a collection of rules for unnecessary,unused or ineffective code. + + + + + + + + + true + true + summarized + + true + Unreachable Code Rules + The Unreachable Code Ruleset contains rules about code sections that can never be executed. + The Unreachable Code Ruleset contains rules about code sections that can never be executed. + + + + + + + + + true + true + summarized + + true + Variable Argument Related Rules + The Variable Argument Related Ruleset contains rules about the usage of va_start and va_end functions. + The Variable Argument Related Ruleset contains rules about the usage of va_start and va_end functions. + + + + + + + diff --git a/cl/Cppcheck2Graph/errorgroups.xml b/cl/Cppcheck2Graph/errorgroups.xml new file mode 100644 index 0000000..8c2afda --- /dev/null +++ b/cl/Cppcheck2Graph/errorgroups.xml @@ -0,0 +1,410 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cl/Cppcheck2Graph/errorlist.xml b/cl/Cppcheck2Graph/errorlist.xml new file mode 100644 index 0000000..1d4e235 --- /dev/null +++ b/cl/Cppcheck2Graph/errorlist.xml @@ -0,0 +1,529 @@ + + + + + + + + + function + + + var + + + + + + + + + + + parameter + + + + + + + + + + + + + + + + + + + + + + + + + i + + + + + func_name + + + func_name + + + func_name + + + malloc + + + + + + + + classname + + + classname + + + var + + + class + + + class + + + class + + + classname::varname + + + classname::varnamepriv + + + classname::varname + + + classname::varnamepriv + + + classname:: + + + classname::funcname + + + memfunc + classname + + + memfunc + + + + malloc + + + malloc + std::string + + + Base + Derived + + + + + + + + class::function + + + class::function + + + class::variable + + + variable + + + var + + + class + variable + class + + + class + + + f + + + + + + + ptr + + + UnsafeClass::var + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + p + + + varname + + + + funcName + + + funcName + + + varname + + + class + class::varname + + + varname + + + varname + + + varname + + + varname + + + + varname + + + varname + + + + pointer + + + pointer + + + + + + + varname + + + + + + varname + + + + + varname + + + var + + + isless + + + func_name + + + + parametername + + + x + + + + + + + varname + + + var + + + var + + + + varname + + + + + + + + + + + + + varname + + + varname + + + + + + buffer + memset + + + + + + varname + + + + + + + + + + + + + + + + + + function + + + varname + + + variable + + + function + + + argument + + + + + + var + + + var + + + function + + + + container + + + iterator + + + container1 + container2 + + + container0 + container1 + + + container + + + + + + + + + iter + + + foo + + + + + + + + + + + + list + + + + + str + find + + + str + + + + + remove + + + i + + + var + + + + + + + + + + + + + + + + + + varname + + + + varname + + + + substr + + + foo + + + foo + + + + + + + + + + + + + + + varname + + + varname + + + varname + + + a.b + + + funcName + + + varname + + + varname + + + varname + + + varname + + + structname::variable + + + + + + + + + + + + + + + diff --git a/cl/Cppcheck2Graph/inc/ResultConverter.h b/cl/Cppcheck2Graph/inc/ResultConverter.h new file mode 100644 index 0000000..66d3bab --- /dev/null +++ b/cl/Cppcheck2Graph/inc/ResultConverter.h @@ -0,0 +1,126 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _CPPCHECK2GRAPH_RESULTCONVERTER_H_ +#define _CPPCHECK2GRAPH_RESULTCONVERTER_H_ + +#include +#include +#include +#include +#include + +#include "XMLParser.h" + + +namespace columbus { namespace cppcheck2graph { + /** + * \brief Class for converting the cppcheck output into warnings, and adding it into the graph. + */ + class ResultConverter: public DefaultHandler { + public: + /** + * \brief Constructor. + * + * \param limFileName The name of the lim file. + * \param txtOutFile The name of the plain text output file. + * \param rulFileName The name of the rul file. + * \param rulConfig Name of the rul config. + * \param exportRul Build the ruls into the graph. + */ + ResultConverter(const std::string& limFileName, const std::string& txtOutFile, const std::string& rulFileName, const std::string& rulConfig, const bool exportRul, const std::string& changePathFrom, const std::string& changePathTo); + + virtual ~ResultConverter(); + + /** + * \brief Process an output file of cppcheck. + * + * \param resultFileName The name of the file. + */ + void process(const std::string& resultFileName); + + /** + * \brief Aggregate warnings. + */ + void aggregateWarnings(); + + /** + * \brief Save the result graph into file. + * + * \param graphOutputFilename The name of the output file. + * \param createXMLdump Create xml dump. + */ + void saveResultGraph(const std::string& graphOutputFilename, bool createXMLdump); + + /** + * \brief Processing the xml opening tags, and creating warnings from the corresponding tags. + */ + virtual void startElement (const XMLCh *const uri, const XMLCh *const localname, const XMLCh *const qname, const Attributes &attrs); + + /** + * \brief Processing the xml ending tags, and creating warnings from the corresponding tags. + */ + virtual void endElement(const XMLCh *const uri, const XMLCh *const localname, const XMLCh *const qname); + + private: + XMLParser parser; + + rul::RulHandler rulHandler; + RefDistributorStrTable limStrTable; + lim::asg::Factory limFactory; + graph::Graph graph; + graphsupport::GraphRangeIndexer& graphIndexer; + + // Variables for xml attribute names. + XMLCh* ruleIdXMLCh; + XMLCh* warningMsgXMLCh; + XMLCh* locationFileXMLCh; + XMLCh* locationFile0XMLCh; + XMLCh* locationLineXMLCh; + + const std::string& changePathFrom; + const std::string& changePathTo; + std::string txtOutFile; + + // Data for the current warning. + std::string id; + std::string warningText; + graphsupport::WarningCache warningCache; + /** + * \brief Structure for a warning location. + */ + struct Location{ + std::string file; + int line; + }; + + // The locations for the current warning. + std::list locations; + + /** + * \brief Add current warning into the graph. + */ + void addWarning(); + }; + +}} + + +#endif diff --git a/cl/Cppcheck2Graph/inc/RuleConverter.h b/cl/Cppcheck2Graph/inc/RuleConverter.h new file mode 100644 index 0000000..221f5dd --- /dev/null +++ b/cl/Cppcheck2Graph/inc/RuleConverter.h @@ -0,0 +1,74 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _CPPCHECK2GRAPH_RULECONVERTER_H_ +#define _CPPCHECK2GRAPH_RULECONVERTER_H_ + + +#include + +#include "XMLParser.h" + + +namespace columbus { namespace cppcheck2graph { + /** + * \brief Class for generating rul file from cppcheck error list. + */ + class RuleConverter { + public: + /** + * \brief Constructor + * + * \param rulConfig Name of the rul config. + */ + RuleConverter(const std::string& rulConfig); + + virtual ~RuleConverter(); + + /** + * \brief Save the rules into a file. + * + * \param rulFileName The output file name. + */ + void saveRulFile(const std::string& rulFileName); + + /** + * \brief Process the cppcheck error list file. + * + * \param configFileName The config file name. + * \param errorListFileName The error list file name. + * \param errorGroupsFileName The error grouping file name. + */ + void process(const std::string& configFileName, const std::string& errorListFileName, const std::string& errorGroupsFileName); + + private: + XMLParser parser; + + rul::RulHandler rulHandler; + + std::map ruleIdMap; + std::map ruleNameMap; + std::map ruleEnabled; + + }; + +}} + +#endif diff --git a/cl/Cppcheck2Graph/inc/XMLParser.h b/cl/Cppcheck2Graph/inc/XMLParser.h new file mode 100644 index 0000000..b803c57 --- /dev/null +++ b/cl/Cppcheck2Graph/inc/XMLParser.h @@ -0,0 +1,51 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _CPPCHECK2GRAPH_XMLPARSER_H_ +#define _CPPCHECK2GRAPH_XMLPARSER_H_ + +#include +#include +#include +#include +#include +#include + +#include +#include + +XERCES_CPP_NAMESPACE_USE + +namespace columbus { namespace cppcheck2graph { + + class XMLParser + { + public: + XMLParser(); + virtual ~XMLParser(); + + void parseXML(const std::string& file, DefaultHandler* handler); + + }; + +}} + + +#endif diff --git a/cl/Cppcheck2Graph/inc/defines.h b/cl/Cppcheck2Graph/inc/defines.h new file mode 100644 index 0000000..22eec31 --- /dev/null +++ b/cl/Cppcheck2Graph/inc/defines.h @@ -0,0 +1,88 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _CPPCHECK2GRAPH_DEFINES_H_ +#define _CPPCHECK2GRAPH_DEFINES_H_ + +#include + +// xml version +#define _RESULT "results" +#define _RESULT_VERSION "version" + +// Rule +#define _RULE "error" +#define _RULE_ID "id" +#define _RULE_PRIORITY "severity" +#define _RULE_WARNING "msg" +#define _RULE_HELP "verbose" +#define _RULE_INCONCLUSIVE "inconclusive" + +// RuleName +#define _RULENAME "rule" + +// Group +#define _GROUPS "groups" +#define _GROUP "group" +#define _GROUP_ID "id" +#define _GROUP_NAME "name" +#define _GROUP_DESCRIPTION "description" +#define _GROUP_HELP "help" +#define _GROUP_RULE "error" +#define _GROUP_RULE_ID "id" + +// Warning +#define _WARNING "error" +#define _WARNING_MSG "msg" +#define _WARNING_LOCATION "location" +#define _WARNING_LOCATION_FILE "file" +#define _WARNING_LOCATION_FILE0 "file0" +#define _WARNING_LOCATION_LINE "line" + +#define _RULE_PREFIX "CPPCHECK_" + + +inline std::string formatDisplayName(const std::string& name){ + + std::ostringstream displaynameS; + + for(std::string::size_type i=0; i < name.length(); ++i){ + if(isupper(name[i]) && i > 0){ + displaynameS << " "; + } + displaynameS << name[i]; + } + + std::string ret = displaynameS.str(); + + ret[0] = toupper(ret[0]); + /* + if(ret.find("Obsolete Functions") != std::string::npos){ + ret = ret.substr(0, 18) + " " + ret.substr(18); + }else if(ret.find("Nonreentrant Functions") != std::string::npos){ + ret = ret.substr(0, 22) + " " + ret.substr(22); + }else if(ret == "Wrongmathcall"){ + ret = "Wrong Math Call"; + }*/ + + return ret; +} + +#endif diff --git a/cl/Cppcheck2Graph/inc/messages.h b/cl/Cppcheck2Graph/inc/messages.h new file mode 100644 index 0000000..74dffda --- /dev/null +++ b/cl/Cppcheck2Graph/inc/messages.h @@ -0,0 +1,35 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _CPPCHECK2GRAPH_MESSAGE_H_ +#define _CPPCHECK2GRAPH_MESSAGE_H_ + +#define CMSG_NO_INPUT_FILE WriteMsg::mlWarning, "Warning: No input file was given!\n" +#define CMSG_NO_OUTPUT_FILE WriteMsg::mlError, "Error: No output file was given!\n\n" +#define CMSG_FAILED_TO_OPEN_FILE WriteMsg::mlError, "Error: File %s can't be opened!\n" +#define CMSG_INTERNAL_ERROR WriteMsg::mlError, "Error: Internal error: %s\n" +#define CMSG_UNABLE_TO_ADD_WARNING_AT_LOCATION WriteMsg::mlWarning, "Warning: Unable to add warning at location: %s(%d)\n" +#define CMSG_WRONG_XML_FORMAT_VERSION WriteMsg::mlWarning, "Warning: The given error list XML file has wrong format version number!\n" +#define CMSG_ORIGINAL_RULE_NOT_EXIST WriteMsg::mlWarning, "Warning: Original rule is not exists: %s\n" +#define CMSG_RULE_NOT_DEFINED WriteMsg::mlWarning, "Warning: Rule is not defined: %s\n" +#define CMSG_RULE_NO_NAME WriteMsg::mlWarning, "Warning: Rule %s does not have name!\n" +#define CMSG_FILE_NOT_EXISTS WriteMsg::mlWarning, "Warning: File does not exists: %s \n" + +#endif diff --git a/cl/Cppcheck2Graph/listerrors.xslt b/cl/Cppcheck2Graph/listerrors.xslt new file mode 100644 index 0000000..46defdf --- /dev/null +++ b/cl/Cppcheck2Graph/listerrors.xslt @@ -0,0 +1,11 @@ + + + + + + + | + + + + diff --git a/cl/Cppcheck2Graph/options.csv b/cl/Cppcheck2Graph/options.csv new file mode 100644 index 0000000..01ae98d --- /dev/null +++ b/cl/Cppcheck2Graph/options.csv @@ -0,0 +1,298 @@ +OriginalID;ID;NewName;Enabled +accessForwarded;AF;Access Forwarded;1 +accessMoved;AM;Access Moved;1 +arithOperationsOnVoidPointer;AOOVP;Arithmetic Operations On Void Pointer;1 +arrayIndexOutOfBounds;AIOOB;Array Index Out Of Bounds;1 +arrayIndexOutOfBoundsCond;AIOOBC;Array Index Out Of Bounds Cond;1 +arrayIndexThenCheck;AITC;Array Index Then Check;1 +assertWithSideEffect;AWSE;Assert With Side Effect;1 +assignBoolToFloat;ABTF;Assign Bool To Float;1 +assignBoolToPointer;ABTP;Assign Bool To Pointer;1 +assignIfError;AIE;Assign If Error;1 +AssignmentAddressToInteger;AATI;Assignment Address To Integer;1 +assignmentInAssert;AIA;Assignment In Assert;1 +assignmentInCondition;AIC;Assignment In Condition;1 +AssignmentIntegerToAddress;AITA;Assignment Integer To Address;1 +autoVariables;AV;Auto Variables;1 +autovarInvalidDeallocation;AID;Autovar Invalid Deallocation;1 +badBitmaskCheck;BBC;Bad Bitmask Check;1 +bitwiseOnBoolean;BOB;Bitwise On Boolean;1 +boostForeachError;BFE;Boost Foreach Error;1 +bufferAccessOutOfBounds;BAOOB;Buffer Access Out Of Bounds;1 +CastAddressToIntegerAtReturn;CATIAR;Cast Address To Integer At Return;1 +CastIntegerToAddressAtReturn;CITAAR;Cast Integer To Address At Return;1 +catchExceptionByValue;CEBV;Catch Exception By Value;1 +charBitOp;CBO;Char Bit Op;1 +charLiteralWithCharPtrCompare;CLWCPC;Char Literal With Char Ptr Compare;1 +checkCastIntToCharAndBack;CCITCAB;Check Cast Int To Char And Back;1 +clarifyCalculation;CCALC;Clarify Calculation;1 +clarifyCondition;CCOND;Clarify Condition;1 +clarifyStatement;CSTAT;Clarify Statement;1 +commaSeparatedReturn;CSR;Comma Separated Return;1 +compareBoolExpressionWithInt;CBEWI;Compare Bool Expression With Int;1 +comparePointers;CP;Compare Pointers;1 +comparisonError;CE;Comparison Error;1 +comparisonFunctionIsAlwaysTrueOrFalse;CFIATOF;Comparison Function Is Always True Or False;1 +comparisonOfBoolWithBoolError;COBWBE;Comparison Of Bool With Bool Error;1 +comparisonOfBoolWithInvalidComparator;COBWIC;Comparison Of Bool With Invalid Comparator;1 +comparisonOfFuncReturningBoolError;COFRBE;Comparison Of Func Returning Bool Error;1 +comparisonOfTwoFuncsReturningBoolError;COTFRBE;Comparison Of Two Funcs Returning Bool Error;1 +constStatement;CS;Const Statement;1 +constVariable;CV;Const Variable;1 +containerOutOfBounds;COOB;Container Out Of Bounds;1 +copyCtorAndEqOperator;CCAEO;Copy Constructor And Eq Operator;1 +copyCtorPointerCopying;CCPC;Copy Ctor Pointer Copying;1 +coutCerrMisusage;CCM;Cout Cerr Misusage;1 +cstyleCast;CSC;Cstyle Cast;1 +danglingLifetime;DL;Dangling Lifetime;1 +danglingReference;DR;Dangling Reference;1 +danglingTemporaryLifetime;DTL;Dangling Temporary Lifetime;1 +danglingTempReference;DTR;Dangling Temporary Reference;1 +deallocDealloc;DD;Dealloc Dealloc;1 +deallocret;DAR;Deallocret;1 +deallocuse;DU;Deallocuse;1 +derefInvalidIterator;DII;Deref Invalid Iterator;1 +divideSizeof;DSO;Divide Sizeof;1 +doubleFree;DF;Double Free;1 +duplicateAssignExpression;DAE;Duplicate Assign Expression;1 +duplicateBranch;DBRANCH;Duplicate Branch;1 +duplicateBreak;DBREAK;Duplicate Break;1 +duplicateCondition;DCOND;Duplicate Condition;1 +duplicateConditionalAssign;DCONDA;Duplicate Condition and Assignement;1 +duplicateExpression;DEXPR;Duplicate Expression;1 +duplicateExpressionTernary;DET;Duplicate Expression Ternary;1 +duplicateValueTernary;DVT;Duplicate Value Ternary;1 +duplInheritedMember;DIM;Dupl Inherited Member;1 +eraseDereference;ED;Erase Dereference;1 +exceptDeallocThrow;EDT;Except Dealloc Throw;1 +exceptRethrowCopy;ERC;Except Rethrow Copy;1 +exceptThrowInDestructor;ETID;Except Throw In Destructor;1 +fflushOnInputStream;FOIS;Fflush On Input Stream;1 +floatConversionOverflow;FCO;Float Conversion Overflow;1 +funcArgNamesDifferent;FAND;Function Argument Names Different;1 +funcArgOrderDifferent;FAOD;Function Argument Order Different;1 +functionConst;FC;Function Const;1 +functionStatic;FS;Function Static;1 +globalLockGuard;GLG;Global Lock Guard;1 +identicalConditionAfterEarlyExit;ICAEE;Identical Condition After Early Exit;1 +identicalInnerCondition;IIC;Identical Inner Condition;1 +ignoredReturnValue;IRV;Ignored Return Value;1 +incompleteArrayFill;IAF;Incomplete Array Fill;1 +incorrectCharBooleanError;ICBE;Incorrect Char Boolean Error;1 +incorrectLogicOperator;ILO;Incorrect Logic Operator;1 +incorrectStringBooleanError;ISBE;Incorrect String Boolean Error;1 +incorrectStringCompare;ISC;Incorrect String Compare;1 +incrementboolean;IB;Increment Boolean;1 +initializerList;IL;Initializer List;1 +integerOverflow;IO;Integer Overflow;1 +invalidContainer;IC;Invalid Container;1 +invalidContainerLoop;ICL;Invalid Container Loop;1 +invalidFree;IF;Invalid Free;1 +invalidFunctionArg;IFA;Invalid Function Arguments;1 +invalidFunctionArgBool;IFAB;Invalid Function Argument Boolean;1 +invalidFunctionArgStr;IFAS;Invalid Function Argument String;1 +invalidIterator1;IIT;Invalid Iterator1;1 +invalidLengthModifierError;ILME;Invalid Length Modifier Error;1 +invalidLifetime;ILT;Invalid Lifetime;1 +invalidPointerCast;IPC;Invalid Pointer Cast;1 +invalidPrintfArgType_float;IPATF;Invalid Printf Arg Type_float;1 +invalidPrintfArgType_n;IPATN;Invalid Printf Arg Type_n;1 +invalidPrintfArgType_p;IPATP;Invalid Printf Arg Type_p;1 +invalidPrintfArgType_s;IPATS;Invalid Printf Arg Type_s;1 +invalidPrintfArgType_sint;IPATSI;Invalid Printf Arg Type_sint;1 +invalidPrintfArgType_uint;IPATUI;Invalid Printf Arg Type_uint;1 +invalidscanf;IS;Invalid Scanf;1 +invalidScanfArgType_float;ISATF;Invalid Scanf Arg Type_float;1 +invalidScanfArgType_int;ISATI;Invalid Scanf Arg Type_int;1 +invalidScanfArgType_s;ISATS;Invalid Scanf Arg Type_s;1 +invalidScanfFormatWidth;ISFW;Invalid Scanf Format Width;1 +invalidScanfFormatWidth_smaller;ISFWS;Invalid Smaller Scanf Format Width;1 +invalidTestForOverflow;ITFO;Invalid Test For Overflow;1 +IOWithoutPositioning;IOWP;IO Without Positioning;1 +iterators1;SIWDC1;Same Iterator With Different Containers1;1 +iterators2;SIWDC2;Same Iterator With Different Containers2;1 +iterators3;SIWDC3;Same Iterator With Different Containers3;1 +knownArgument;KA;Known Argument;1 +knownArgumentHiddenVariableExpression;KAHVE;Known Argument Hidden Variable Expression;1 +knownConditionTrueFalse;CAF;Condition is Always False;1 +knownEmptyContainer;KEC;Known Empty Container;1 +leakNoVarFunctionCall;LNVFC;Leak No Var Function Call;1 +leakReturnValNotUsed;LRVNU;Leak Return Val Not Used;1 +leakUnsafeArgAlloc;UA;Unsafe allocation;1 +literalWithCharPtrCompare;VCWSL;Variable Comparison With String Literal;1 +localMutex;LM;Local Mutex;1 +mallocOnClassError;MOCE;Malloc On Class Error;1 +mallocOnClassWarning;MOCW;Malloc On Class Warning;1 +memleak;ML;Memleak;1 +memleakOnRealloc;MOR;Memleak On Realloc;1 +memsetClass;MC;Memset Class;1 +memsetClassFloat;MCF;Memset Class Float;1 +memsetClassReference;MCR;Memset Class Reference;1 +memsetFloat;MF;Memset Float;1 +memsetValueOutOfRange;MVOOR;Memset Value Out Of Range;1 +memsetZeroBytes;MZB;Memset Zero Bytes;1 +mismatchAllocDealloc;MAD;Mismatch Alloc Dealloc;1 +mismatchingBitAnd;MBA;Mismatching Bit And;1 +mismatchingContainerExpression;MCE;Mismatching Container Expression;1 +mismatchingContainerIterator;MCI;Mismatching Container Iterator;1 +mismatchingContainers;MMC;Mismatching Containers;1 +mismatchSize;MS;Mismatch Size;1 +missingOverride;MO;Missing Override;1 +moduloAlwaysTrueFalse;MATF;Modulo Always True False;1 +moduloofone;MOO;Modulo Of One;1 +multiCondition;MCOND;Multi Condition;1 +multiplySizeof;MSO;Multiply Sizeof;1 +nanInArithmeticExpression;NIAE;Nan In Arithmetic Expression;1 +negativeContainerIndex;NCI;Negative Container Index;1 +negativeIndex;NI;Negative Index;1 +noConstructor;NC;No Constructor;1 +noCopyConstructor;NCC;No Copy Constructor;1 +noDestructor;ND;No Destructor;1 +noExplicitConstructor;NEC;No Explicit Constructor;1 +noOperatorEq;NAO;No Assignment Operator;1 +nullPointer;NP;Null Pointer;1 +nullPointerArithmetic;PAWN;Pointer Arithmetic With NULL;1 +nullPointerArithmeticRedundantCheck;PAORCWN;Pointer Arithmetic Or Redundant Check With NULL;1 +nullPointerDefaultArg;NPDWDA;NULL Pointer Dereference With Default Argument;1 +nullPointerRedundantCheck;RNPC;Redundant NULL Pointer Check;1 +objectIndex;OI;Object Index;1 +operatorEqMissingReturnStatement;MRFAO;Missing Return From Assignement Operator;1 +operatorEqRetRefThis;OERRT;Operator Eq Ret Ref This;1 +operatorEqShouldBeLeftUnimplemented;AOSBLU;Assignment Operator Should Be Left Unimplemented;1 +operatorEqToSelf;OETS;Operator Eq To Self;1 +operatorEqVarError;OEVE;Operator Eq Var Error;1 +oppositeExpression;OPE;Opposite Expression;1 +oppositeInnerCondition;OIC;Opposite Inner Condition;1 +overlappingStrcmp;OS;Overlapping Strcmp;1 +passedByValue;PBV;Passed By Value;1 +pointerAdditionResultNotNull;PANC;Pointer Addition Null Check;1 +pointerArithBool;PAB;Pointer Arith Bool;1 +pointerLessThanZero;PLTZ;Pointer Less Than Zero;1 +pointerOutOfBounds;POOB;Pointer Out Of Bounds;1 +pointerPositive;PP;Pointer Positive;1 +pointerSize;PS;Pointer Size;1 +postfixOperator;PO;Postfix Operator;1 +preprocessorErrorDirective;PED;Preprocessor Error Directive;0 +publicAllocationError;PAE;Public Allocation Error;1 +pureVirtualCall;PVC;Pure Virtual Call;1 +raceAfterInterlockedDecrement;RAID;Race After Interlocked Decrement;1 +reademptycontainer;REC;Read Empty Container;1 +readWriteOnlyFile;RWOF;Read Write Only File;1 +redundantAssignInSwitch;RAIS;Redundant Assign In Switch;1 +redundantAssignment;RA;Redundant Assignment;1 +redundantBitwiseOperationInSwitch;RBOIS;Redundant Bitwise Operation In Switch;1 +redundantCondition;RCOND;Redundant Condition;1 +redundantCopy;RCPY;Redundant Copy;1 +redundantCopyInSwitch;RCIS;Redundant Copy In Switch;1 +redundantCopyLocalConst;RCLC;Redundant Copy Local Const;1 +redundantIfRemove;RIR;Redundant If Remove;1 +redundantInitialization;RI;Redundant Initialization;1 +redundantPointerOp;RPO;Redundant Pointer Operation;1 +resourceLeak;RL;Resource Leak;1 +rethrowNoCurrentException;NCETR;No Current Exception To Rethrow ;1 +returnAddressOfAutoVariable;RAOAV;Return Address Of Auto Variable;1 +returnAddressOfFunctionParameter;RAOFP;Return Address Of Function Parameter;1 +returnDanglingLifetime;RDL;Return Dangling Lifetime;1 +returnLocalVariable;RLV;Return Local Variable;1 +returnNonBoolInBooleanFunction;RNBIBF;Return Address Of Auto Variable;1 +returnReference;RF;Return Reference;1 +returnTempReference;RTF;Return Temp Reference;1 +sameIteratorExpression;SIE;Same Iterator Expression;1 +seekOnAppendedFile;SOAF;Seek On Appended File;1 +selfAssignment;SA;Self Assignment;1 +selfInitialization;SI;Self Initialization;1 +shadowArgument;SAR;Shadow Argument;1 +shadowFunction;SF;Shadow Function;1 +shadowVariable;SV;Shadow Variable;1 +shiftNegative;SBN;Shift By Negative;1 +shiftNegativeLHS;SN;Shift Negative;1 +shiftTooManyBits;STMB;Shift Too Many Bits;1 +shiftTooManyBitsSigned;STMBS;Shift Too Many Bits Signed;1 +signConversion;SC;Sign Conversion;1 +signedCharArrayIndex;SCAI;Signed Char Array Index;1 +sizeofCalculation;SOC;Sizeof Calculation;1 +sizeofDereferencedVoidPointer;SODVP;Sizeof Dereferenced Void Pointer;1 +sizeofDivisionMemfunc;SODMF;Sizeof Division Memfunc;1 +sizeofFunctionCall;SOFC;Sizeof Function Call;1 +sizeofsizeof;SOSO;Sizeof Sizeof;1 +sizeofVoid;SOV;Sizeof Void;1 +sizeofwithnumericparameter;SOWNP;Sizeof With Numeric Parameter;1 +sizeofwithsilentarraypointer;SOWSAP;Sizeof With Silent Array Pointer;1 +sprintfOverlappingData;SOD;Sprintf Overlapping Data;1 +staticStringCompare;SSC;Static String Compare;1 +stlBoundaries;STLB;Stl Boundaries;1 +stlcstr;STLC;Stlcstr;1 +stlcstrParam;SCP;Stlcstr Param;1 +stlcstrReturn;SCR;Stlcstr Return;1 +stlcstrthrow;SCT;Stlcstr Throw;1 +stlFindInsert;STLFBI;Stl Find Before Insert;1 +stlIfFind;STLIF;Stl If Find;1 +stlIfStrFind;STLISF;Stl If Str Find;1 +StlMissingComparison;STLMC;Stl Missing Comparison;1 +stlOutOfBounds;STLOOB;Stl Out Of Bounds;1 +stlSize;STLS;Stl Size;1 +stringCompare;STRCMP;String Compare;1 +stringLiteralWrite;SLW;String Literal Write;1 +strPlusChar;SPC;Str Plus Char;1 +suspiciousCase;SUSPC;Suspicious Case;1 +suspiciousSemicolon;SS;Suspicious Semicolon;1 +thisSubtraction;TS;This Subtraction;1 +thisUseAfterFree;TUAF;This Is Used After Free;1 +throwInNoexceptFunction;TINF;Throw In Noexcept Function;1 +truncLongCastAssignment;TLCA;Trunc Long Cast Assignment;1 +truncLongCastReturn;TLCR;Trunc Long Cast Return;1 +unassignedVariable;UAV;Unassigned Variable;1 +unhandledExceptionSpecification;UES;Unhandled Exception Specification;1 +uninitdata;UID;Uninitialized Data;1 +uninitDerivedMemberVar;UDMV;Uninitialized Derived Member Variable;1 +uninitDerivedMemberVarPrivate;UDPMV;Uninitialized Derived Private Member Variable;1 +uninitMemberVar;UMV;Uninitialized Member Variable;1 +uninitMemberVarPrivate;UPMV;Uninitialized Private Member Variable;1 +uninitstring;DUOS;Dangerous Use Of Strncpy;1 +uninitStructMember;UISM;Uninit Struct Member;1 +uninitvar;UIV;Uninitialized Variable;1 +unknownEvaluationOrder;UEO;Unknown Evaluation Order;1 +unknownSignCharArrayIndex;CAI;Character Array Index;1 +unpreciseMathCall;UPMC;Unprecise Math Call;1 +unreachableCode;URC;Unreachable Code;1 +unreadVariable;URV;Unread Variable;1 +unsafeClassCanLeak;UCCL;Unsafe Class Can Leak;1 +unsafeClassRefMember;UCRM;Unsafe Class Reference Member;1 +unsignedLessThanZero;ULTZ;Unsigned Less Than Zero;1 +unsignedPositive;UP;Unsigned Positive;1 +unusedAllocatedMemory;UUAM;Unused Allocated Memory;1 +unusedFunction;UUF;Unused Function;1 +unusedLabel;UL;Unused Label;1 +unusedLabelConfiguration;ULITC;Unused Label In This Configuration;1 +unusedLabelSwitch;USL;Unused Switch Label;1 +unusedLabelSwitchConfiguration;USLITC;Unused Switch Label in This Configuration;1 +unusedPrivateFunction;UPF;Unused Private Function;1 +unusedScopedObject;UUSO;Unused Scoped Object;1 +unusedStructMember;UUSM;Unused Struct Member;1 +unusedVariable;UUV;Unused Variable;1 +useClosedFile;UCF;Use Closed File;1 +useInitializationList;UIL;Use Initialization List;1 +uselessAssignmentArg;UAA;Useless Assignment Arg;1 +uselessAssignmentPtrArg;UAPARG;Useless Assignment Ptr Arg;1 +uselessCallsCompare;UCC;Useless Calls Compare;1 +uselessCallsEmpty;UCE;Useless Calls Empty;1 +uselessCallsRemove;UCR;Useless Calls Remove;1 +uselessCallsSubstr;UCSS;Useless Calls Substr;1 +uselessCallsSwap;UCS;Useless Calls Swap;1 +useStlAlgorithm;USA;Use STL Algorithm;1 +va_end_missing;VAEM;Va_end Missing;1 +va_list_usedBeforeStarted;VALUBS;Va_list Used Before Started;1 +va_start_referencePassed;VASRP;Va_start Reference Passed;1 +va_start_subsequentCalls;VASSC;Va_start Subsequent Calls;1 +va_start_wrongParameter;VASWP;Va_start Wrong Parameter;1 +varFuncNullUB;VFNUB;Var Func Null UB;1 +variableScope;VS;Variable Scope;1 +virtualCallInConstructor;VCIC;Virtual Call In Constructor;1 +virtualDestructor;VD;Virtual Destructor;1 +writeReadOnlyFile;WROF;Write Read Only File;1 +wrongmathcall;WMC;Wrong Math Call;1 +wrongPipeParameterSize;WPPS;Wrong Pipe Parameter Size;1 +wrongPrintfScanfArgNum;WPSAN;Wrong Printf Scanf Arg Num;1 +wrongPrintfScanfParameterPositionError;WPSPPE;Wrong Printf Scanf Parameter Position Error;1 +zerodiv;ZD;Zerodiv;1 +zerodivcond;ZDC;Zerodivcond;1 diff --git a/cl/Cppcheck2Graph/src/ResultConverter.cpp b/cl/Cppcheck2Graph/src/ResultConverter.cpp new file mode 100644 index 0000000..c2ad0e5 --- /dev/null +++ b/cl/Cppcheck2Graph/src/ResultConverter.cpp @@ -0,0 +1,249 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + + +#include +#include +#include +#include +#include +#include "../inc/ResultConverter.h" +#include "../inc/messages.h" +#include "../inc/defines.h" + +using namespace std; +using namespace common; +using namespace columbus; +using namespace columbus::graph; +using namespace columbus::cppcheck2graph; + + +ResultConverter::ResultConverter(const std::string& limFileName, const std::string& txtOutFile, const std::string& rulFileName, const std::string& rulConfig, const bool exportRul, const std::string& changePathFrom, const std::string& changePathTo): + DefaultHandler(), + parser(), + rulHandler(rulFileName, rulConfig, "eng"), + limStrTable(), + limFactory(limStrTable, "", columbus::lim::asg::limLangOther), + graphIndexer(graphsupport::GraphRangeIndexer::getGraphRangeIndexerInstance()), + changePathFrom(changePathFrom), + changePathTo(changePathTo), + txtOutFile(txtOutFile) +{ + // Loading lim + list headerDataList; + limFactory.load(limFileName, headerDataList); + loadFilter(limFactory, limFileName, ".flim"); + lim2graph::convertBaseGraph(limFactory, graph, true, true, true, true, false); + graphIndexer.turnOn(graph); + if(exportRul) { + graphsupport::buildRulToGraph(graph, rulHandler); + } + + // Xml attribute names + ruleIdXMLCh = XMLString::transcode(_RULE_ID); + warningMsgXMLCh = XMLString::transcode(_WARNING_MSG); + locationFileXMLCh = XMLString::transcode(_WARNING_LOCATION_FILE); + locationFile0XMLCh = XMLString::transcode(_WARNING_LOCATION_FILE0); + locationLineXMLCh = XMLString::transcode(_WARNING_LOCATION_LINE); + + // Creating empty text output file + if(!txtOutFile.empty()) { + std::ofstream out(txtOutFile.c_str()); + if(!out) { + WriteMsg::write(CMSG_FAILED_TO_OPEN_FILE, txtOutFile.c_str()); + } else { + out << ""; + } + } +} + +ResultConverter::~ResultConverter(){ + XMLString::release(&ruleIdXMLCh); + XMLString::release(&warningMsgXMLCh); + XMLString::release(&locationFileXMLCh); + XMLString::release(&locationFile0XMLCh); + XMLString::release(&locationLineXMLCh); +} + +void ResultConverter::process(const std::string& resultFileName){ + parser.parseXML(resultFileName, this); +} + +void ResultConverter::saveResultGraph(const std::string& graphOutputFilename, bool createXMLdump) { + graph.saveBinary(graphOutputFilename); + if (createXMLdump) { + graph.saveXML(common::pathRemoveExtension(graphOutputFilename) + ".xml"); + } +} + +void ResultConverter::addWarning(){ + string ruleId; + try{ + ruleId = rulHandler.getRuleIdByOriginalId(id); + }catch(rul::RulHandlerException &){ + WriteMsg::write(CMSG_ORIGINAL_RULE_NOT_EXIST, id.c_str()); + return; + } + if (!rulHandler.getIsDefined(ruleId)) { + WriteMsg::write(CMSG_RULE_NOT_DEFINED, ruleId.c_str()); + return; + } + if (!rulHandler.getIsEnabled(ruleId)) { + return; // rule is not enabled + } + + list nodes; + // The last location is the place of the warning + Location location = locations.back(); + locations.pop_back(); + // Find nodes at location + common::pathCanonicalize(location.file, location.file); + location.file = common::replace(location.file.c_str(), changePathFrom.c_str(), changePathTo.c_str()); + if (graphIndexer.findNodesByRange(graph, location.file, location.line, 0, location.line, INT_MAX, nodes)) { + int minDist = INT_MAX; + Node node; + // Find the closest one + for(list::iterator it = nodes.begin(); it != nodes.end(); ++it) { + vector positions; + graphsupport::getPositionAttributes(*it, positions); + for(vector::iterator pos = positions.begin(); pos != positions.end(); ++pos) { + if((abs(location.line-pos->line) + abs(location.line-pos->endline)) < minDist) { + node = *it; + minDist = abs(location.line-pos->line) + abs(location.line-pos->endline); + } + } + } + + // If the found node is an attribute, we use its parent + if(node != Graph::invalidNode) { + if(node.getType().getType() == graphsupport::graphconstants::NTYPE_LIM_ATTRIBUTE) { + Edge::EdgeIterator edgeIt = node.findOutEdges(Edge::EdgeType(graphsupport::graphconstants::ETYPE_LIM_LOGICALTREE, Edge::edtReverse)); + if(edgeIt.hasNext()) { + node = edgeIt.next().getToNode(); + } + } + } + + if (node != Graph::invalidNode) { + bool warningAdded = false; + // If there is more location, then we creating extraInfo attribute + if (locations.size() != 0) { + AttributeComposite extraInfo = graph.createAttributeComposite(graphsupport::graphconstants::ATTR_EXTRAINFO, graphsupport::graphconstants::CONTEXT_TRACE); + for(list::iterator it = locations.begin(); it != locations.end(); ++it) + { + common::pathCanonicalize(it->file, it->file); + it->file = common::replace(it->file.c_str(), changePathFrom.c_str(), changePathTo.c_str()); + extraInfo.addAttribute(graphsupport::createSourceLinkAttribute(graph, it->file, it->line)); + } + + warningAdded = graphsupport::addWarningOnce(graph, node, ruleId, location.file, location.line, 0, location.line, 10000, warningText, extraInfo, &warningCache); + } else{ + warningAdded = graphsupport::addWarningOnce(graph, node, ruleId, location.file, location.line, 0, location.line, 10000, warningText, &warningCache); + } + + if (warningAdded){ + if(!txtOutFile.empty()) { + std::ofstream out(txtOutFile.c_str(), std::ofstream::out | std::ofstream::app); + if(!out) { + WriteMsg::write(CMSG_FAILED_TO_OPEN_FILE, txtOutFile.c_str()); + }else{ + out << location.file << "(" << location.line << "): " << ruleId << ": " << warningText << std::endl; + } + } + } + } + else + { + WriteMsg::write(CMSG_UNABLE_TO_ADD_WARNING_AT_LOCATION, location.file.c_str(), location.line); + } + } + else + { + WriteMsg::write(CMSG_UNABLE_TO_ADD_WARNING_AT_LOCATION, location.file.c_str(), location.line); + } +} + +void ResultConverter::aggregateWarnings() { + graphsupport::cumSum(graph, graph::Edge::EdgeType(graphsupport::graphconstants::ETYPE_LIM_COMPONENT, graph::Edge::edtDirectional), true, std::set(), true); + graphsupport::cumSum(graph, graph::Edge::EdgeType(graphsupport::graphconstants::ETYPE_LIM_LOGICALTREE, graph::Edge::edtReverse), false); + + graphsupport::createGroupMetrics(graph, rulHandler); +} + +void ResultConverter::startElement (const XMLCh *const uri, const XMLCh *const localname, const XMLCh *const qname, const Attributes &attrs){ + char* localnameChar = XMLString::transcode(localname); + if(strcmp(localnameChar, _WARNING) == 0) { + const XMLCh* ruleId = attrs.getValue(ruleIdXMLCh); + const XMLCh* warningMsg = attrs.getValue(warningMsgXMLCh); + + char* ruleIdChar = XMLString::transcode(ruleId); + char* warningMsgChar = XMLString::transcode(warningMsg); + + // Set the current warning's data + id = ruleIdChar; + warningText = warningMsgChar; + + XMLString::release(&ruleIdChar); + XMLString::release(&warningMsgChar); + } + else if(strcmp(localnameChar, _WARNING_LOCATION) == 0) { + const XMLCh* locationFile = attrs.getValue(locationFileXMLCh); + const XMLCh* locationFile0 = attrs.getValue(locationFile0XMLCh); + const XMLCh* locationLine = attrs.getValue(locationLineXMLCh); + + char* locationFileChar = XMLString::transcode(locationFile); + char* locationFile0Char = locationFile0 ? XMLString::transcode(locationFile0) : nullptr; + char* locationLineChar = XMLString::transcode(locationLine); + + // Creating and adding the location to the current warning's locations + Location location; + + if (locationFile0Char == nullptr) + location.file = locationFileChar; + else + { + if (!common::pathIsRelative(locationFileChar)) + location.file = locationFileChar; + else + location.file = common::pathRemoveFileSpec(locationFile0Char) + DIRDIVSTRING + locationFileChar; + } + + + location.line = atoi(locationLineChar); + locations.push_back(location); + + XMLString::release(&locationFileChar); + XMLString::release(&locationLineChar); + } + XMLString::release(&localnameChar); +} + +void ResultConverter::endElement(const XMLCh *const uri, const XMLCh *const localname, const XMLCh *const qname){ + char* localnameChar = XMLString::transcode(localname); + if(strcmp(localnameChar, _WARNING) == 0) { + // If the warning has location, then add it to the graph + if(locations.size()>0){ + addWarning(); + locations.clear(); + id.clear(); + } + } + XMLString::release(&localnameChar); +} diff --git a/cl/Cppcheck2Graph/src/RuleConverter.cpp b/cl/Cppcheck2Graph/src/RuleConverter.cpp new file mode 100644 index 0000000..6efebe4 --- /dev/null +++ b/cl/Cppcheck2Graph/src/RuleConverter.cpp @@ -0,0 +1,307 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "../inc/RuleConverter.h" +#include "../inc/messages.h" +#include "../inc/defines.h" + +#include + +using namespace std; +using namespace common; +using namespace columbus; +using namespace columbus::cppcheck2graph; + + + +class RuleHandler : public DefaultHandler { +private: + + rul::RulHandler& rulHandler; + + // Variables for xml attribute names. + XMLCh* ruleIdXMLCh; + XMLCh* rulePriorityXMLCh; + XMLCh* ruleWarningXMLCh; + XMLCh* ruleHelpXMLCh; + XMLCh* ruleInconclusiveXMLCh; + XMLCh* resultVersionXMLCh; + + map& ruleIdMap; + map& ruleNameMap; + map& ruleEnabled; + +public: + RuleHandler(rul::RulHandler& _rulHandler, map& _ruleIdMap, map& _ruleNameMap, map& _ruleEnabled): + DefaultHandler(), + rulHandler(_rulHandler), + ruleIdMap(_ruleIdMap), + ruleNameMap(_ruleNameMap), + ruleEnabled(_ruleEnabled) + { + // Xml attribute names + ruleIdXMLCh = XMLString::transcode(_RULE_ID); + rulePriorityXMLCh = XMLString::transcode(_RULE_PRIORITY); + ruleWarningXMLCh = XMLString::transcode(_RULE_WARNING); + ruleHelpXMLCh = XMLString::transcode(_RULE_HELP); + ruleInconclusiveXMLCh = XMLString::transcode(_RULE_INCONCLUSIVE); + resultVersionXMLCh = XMLString::transcode(_RESULT_VERSION); + } + + ~RuleHandler(){ + // Xml attribute names + XMLString::release(&ruleIdXMLCh); + XMLString::release(&rulePriorityXMLCh); + XMLString::release(&ruleWarningXMLCh); + XMLString::release(&ruleHelpXMLCh); + XMLString::release(&ruleInconclusiveXMLCh); + XMLString::release(&resultVersionXMLCh); + } + + virtual void startElement (const XMLCh *const uri, const XMLCh *const localname, const XMLCh *const qname, const Attributes &attrs){ + char* localnameChar = XMLString::transcode(localname); + if(strcmp(localnameChar, _RULE) == 0) { + const XMLCh* ruleId = attrs.getValue(ruleIdXMLCh); + const XMLCh* rulePriority = attrs.getValue(rulePriorityXMLCh); + const XMLCh* ruleWarning = attrs.getValue(ruleWarningXMLCh); + const XMLCh* ruleHelp= attrs.getValue(ruleHelpXMLCh); + //const XMLCh* ruleInconclusive= attrs.getValue(ruleInconclusiveXMLCh); + + char* ruleIdChar = XMLString::transcode(ruleId); + char* rulePriorityChar = XMLString::transcode(rulePriority); + char* ruleWarningChar = XMLString::transcode(ruleWarning); + char* ruleHelpChar = XMLString::transcode(ruleHelp); + + string name = ruleIdChar; + string priority = rulePriorityChar; + string warning = ruleWarningChar; + string help = ruleHelpChar; + + if(priority == "error") + priority = "Blocker"; + else if(priority == "warning") + priority = "Critical"; + else if(priority == "performance") + priority = "Major"; + else if(priority == "style") + priority = "Minor"; + else if(priority == "portability") + priority = "Minor"; + else if(priority == "information") + priority = "Info"; + + string id = _RULE_PREFIX; + id += ruleIdMap[name]; + + if( id != _RULE_PREFIX ) { + + /* + if(ruleInconclusive){ + } + */ + + rulHandler.defineMetric(id); + rulHandler.createConfiguration(id, rulHandler.getConfig()); + rulHandler.setIsEnabled(id, ruleEnabled[name]); + rulHandler.createLanguage(id, "eng"); + rulHandler.setHasWarningText(id, true); + rulHandler.setSettingValue(id, "Priority", priority, true); + rulHandler.setGroupType(id, "false"); + rulHandler.setOriginalId(id, name); + + string displayName = ruleNameMap[name];//formatDisplayName(name); + rulHandler.setDisplayName(id, displayName); + rulHandler.setDescription(id, ""); + rulHandler.setHelpText(id, help); + //rulHandler.setWarningText(id, warning); + + } else { + + WriteMsg::write(CMSG_RULE_NO_NAME, name.c_str()); + + } + + XMLString::release(&ruleIdChar); + XMLString::release(&rulePriorityChar); + XMLString::release(&ruleWarningChar); + XMLString::release(&ruleHelpChar); + + }else if(strcmp(localnameChar, _RESULT) == 0) { + const XMLCh* resultVersion = attrs.getValue(resultVersionXMLCh); + bool versionOk = false; + if(resultVersion){ + char* resultVersionChar = XMLString::transcode(resultVersion); + + if(strcmp(resultVersionChar, "2") == 0){ + versionOk = true; + } + + XMLString::release(&resultVersionChar); + } + if(!versionOk){ + WriteMsg::write(CMSG_WRONG_XML_FORMAT_VERSION); + } + } + XMLString::release(&localnameChar); + } +}; + + + + +class GroupHandler : public DefaultHandler { +private: + rul::RulHandler& rulHandler; + + // Variables for xml attribute names. + XMLCh* groupIdXMLCh; + XMLCh* groupNameXMLCh; + XMLCh* groupDescriptionXMLCh; + XMLCh* groupHelpXMLCh; + XMLCh* groupRuleIdXMLCh; + + // Data for the current group. + std::string id; + + map& nameMap; + +public: + GroupHandler(rul::RulHandler& _rulHandler, map& _nameMap): + DefaultHandler(), + rulHandler(_rulHandler), + nameMap(_nameMap) + { + // Xml attribute names + groupIdXMLCh = XMLString::transcode(_GROUP_ID); + groupNameXMLCh = XMLString::transcode(_GROUP_NAME); + groupDescriptionXMLCh = XMLString::transcode(_GROUP_DESCRIPTION); + groupHelpXMLCh = XMLString::transcode(_GROUP_HELP); + groupRuleIdXMLCh = XMLString::transcode(_GROUP_RULE_ID); + } + + ~GroupHandler(){ + // Xml attribute names + XMLString::release(&groupIdXMLCh); + XMLString::release(&groupNameXMLCh); + XMLString::release(&groupDescriptionXMLCh); + XMLString::release(&groupHelpXMLCh); + XMLString::release(&groupRuleIdXMLCh); + } + + virtual void startElement (const XMLCh *const uri, const XMLCh *const localname, const XMLCh *const qname, const Attributes &attrs){ + char* localnameChar = XMLString::transcode(localname); + if(strcmp(localnameChar, _GROUP) == 0) { + const XMLCh* groupId = attrs.getValue(groupIdXMLCh); + const XMLCh* groupName= attrs.getValue(groupNameXMLCh); + const XMLCh* groupDescription = attrs.getValue(groupDescriptionXMLCh); + const XMLCh* groupHelp= attrs.getValue(groupHelpXMLCh); + + char* groupIdChar = XMLString::transcode(groupId); + char* groupNameChar = XMLString::transcode(groupName); + char* groupDescriptionChar = XMLString::transcode(groupDescription); + char* groupHelpChar = XMLString::transcode(groupHelp); + + id = groupIdChar; + string name = groupNameChar; + string description = groupDescriptionChar; + string help = groupHelpChar; + + + rulHandler.defineMetric(id); + rulHandler.createConfiguration(id, rulHandler.getConfig()); + rulHandler.setIsEnabled(id, true); + rulHandler.createLanguage(id, "eng"); + rulHandler.setHasWarningText(id, true); + rulHandler.setIsVisible(id, true); + rulHandler.setGroupType(id, "summarized"); + + + rulHandler.setDisplayName(id, name); + rulHandler.setDescription(id, description); + rulHandler.setHelpText(id, help); + + + XMLString::release(&groupIdChar); + XMLString::release(&groupNameChar); + XMLString::release(&groupDescriptionChar); + XMLString::release(&groupHelpChar); + + }else if(strcmp(localnameChar, _GROUP_RULE) == 0) { + const XMLCh* ruleId = attrs.getValue(groupRuleIdXMLCh); + + char* ruleIdChar = XMLString::transcode(ruleId); + + string ruleIdStr = ruleIdChar; + ruleIdStr = _RULE_PREFIX + nameMap[ruleIdStr]; + + try{ + rulHandler.addMetricGroupMembers(ruleIdStr, id); + }catch(rul::RulHandlerException &e){ + WriteMsg::write(WriteMsg::mlWarning, "%s\n", e.getMessage().c_str()); + } + + XMLString::release(&ruleIdChar); + + } + } +}; + + +RuleConverter::RuleConverter(const std::string& rulConfig): + parser(), + rulHandler(rulConfig, "eng") +{ + rulHandler.setToolDescription("ID", "Cppcheck"); +} + +RuleConverter::~RuleConverter(){ +} + +void RuleConverter::process(const std::string& configFileName, const std::string& errorListFileName, const std::string& errorGroupsFileName){ + + io::CsvIO options(configFileName, io::IOBase::omRead); + + vector line; + options.readLine(line); + line.clear(); + + while(options.readLine(line)){ + string oid = line[0]; + string id = line[1]; + string newname = line[2]; + bool enabled = line[3]=="1"; + + ruleIdMap.insert(make_pair(oid, id)); + ruleNameMap.insert(make_pair(oid, newname)); + ruleEnabled.insert(make_pair(oid, enabled)); + + line.clear(); + } + + RuleHandler ruleHandler(rulHandler, ruleIdMap, ruleNameMap, ruleEnabled); + parser.parseXML(errorListFileName, &ruleHandler); + + GroupHandler groupHandler(rulHandler, ruleIdMap); + parser.parseXML(errorGroupsFileName, &groupHandler); +} + +void RuleConverter::saveRulFile(const std::string& rulFileName){ + rulHandler.saveRul(rulFileName); +} diff --git a/cl/Cppcheck2Graph/src/XMLParser.cpp b/cl/Cppcheck2Graph/src/XMLParser.cpp new file mode 100644 index 0000000..723cfd6 --- /dev/null +++ b/cl/Cppcheck2Graph/src/XMLParser.cpp @@ -0,0 +1,81 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "../inc/XMLParser.h" +#include "../inc/messages.h" + +using namespace std; +using namespace common; +using namespace columbus; +using namespace columbus::cppcheck2graph; + + +XMLParser::XMLParser(){ + try { + XMLPlatformUtils::Initialize(); + }catch (const XMLException& toCatch) { + char* message = XMLString::transcode(toCatch.getMessage()); + string exceptionMessage = message; + XMLString::release(&message); + throw Exception("XMLParser::XMLParser", exceptionMessage); + } +} + +XMLParser::~XMLParser() { + try { + XMLPlatformUtils::Terminate(); + } + catch (const XMLException& toCatch) + { + char* message = XMLString::transcode(toCatch.getMessage()); + string exceptionMessage = message; + XMLString::release(&message); + WriteMsg::write(CMSG_INTERNAL_ERROR, exceptionMessage.c_str()); + } +} + +void XMLParser::parseXML(const std::string& file, DefaultHandler* handler) { + + SAX2XMLReader* parser = XMLReaderFactory::createXMLReader(); + parser->setFeature(XMLUni::fgSAX2CoreValidation, true); + parser->setFeature(XMLUni::fgSAX2CoreNameSpaces, true); + parser->setFeature(XMLUni::fgXercesSchema, false); + parser->setFeature(XMLUni::fgXercesLoadExternalDTD, false); + + parser->setContentHandler(handler); + parser->setErrorHandler(handler); + + try { + LocalFileInputSource source(XMLString::transcode(file.c_str())); + parser->parse(source); + }catch (const XMLException& toCatch) { + char* message = XMLString::transcode(toCatch.getMessage()); + string exceptionMessage = message; + XMLString::release(&message); + throw Exception("XMLParser::parseXML",exceptionMessage); + }catch (const SAXParseException& toCatch) { + char* message = XMLString::transcode(toCatch.getMessage()); + string exceptionMessage = message; + XMLString::release(&message); + throw Exception("XMLParser::parseXML",exceptionMessage); + } + + delete parser; +} diff --git a/cl/Cppcheck2Graph/src/main.cpp b/cl/Cppcheck2Graph/src/main.cpp new file mode 100644 index 0000000..00e50b8 --- /dev/null +++ b/cl/Cppcheck2Graph/src/main.cpp @@ -0,0 +1,164 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#define PROGRAM_NAME "Cppcheck2Graph" +#define EXECUTABLE_NAME "Cppcheck2Graph" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../inc/RuleConverter.h" +#include "../inc/ResultConverter.h" +#include "../inc/messages.h" + +using namespace std; +using namespace common; +using namespace columbus; +using namespace columbus::cppcheck2graph; + +static string configFileName; +static string errorListFileName; +static string groupsFileName; +static string graphFileName; +static string outputFileName; +static string limFileName; +static string rul_s = "Cppcheck.rul"; +static string rulConfig = "Default"; +static bool exportRul = false; +static string fList; +static list listOfFile; +static size_t peakMemory = 0; + +static bool ppMakeRul(const Option *o, char *argv[]) { + errorListFileName = argv[0]; + groupsFileName = argv[1]; + configFileName = argv[2]; + return true; +} + +static bool ppGraph(const Option *o, char *argv[]) { + graphFileName = argv[0]; + return true; +} + +static bool ppOut(const Option *o, char *argv[]) { + outputFileName = argv[0]; + return true; +} + +static bool ppLimFile(const Option *o, char *argv[]) { + limFileName = argv[0]; + return true; +} + +static bool ppRul (const Option *o, char *argv[]) { + rul_s = argv[0]; + return true; +} + +static bool ppRulConfig (const Option *o, char *argv[]) { + rulConfig = argv[0]; + return true; +} + +static bool ppExportRul(const Option *o, char *argv[]) { + exportRul = true; + return true; +} + +static bool ppList(const Option *o, char *argv[]) { + fList = argv[0]; + return true; +} + +static void ppFile(char *filename) { + listOfFile.push_back(filename); +} + + +const common::Option OPTIONS_OBJ [] = { + { false, "-makerul", 3, "errorlist.xml errorgroups.xml options.csv", 0, OT_WS, ppMakeRul, NULL, "Making rul file from the error list of the cppcheck (2. version of the XML file is required)."}, + { false, "-graph", 1, "filename", 0, OT_WC, ppGraph, NULL, "Save binary graph output."}, + { false, "-out", 1, "filename", 0, OT_WC, ppOut, NULL, "Specify the name of the output file. The list of rule violations will be dumped in it.\n"}, + CL_INPUT_LIST + CL_LIM + CL_RUL_AND_RULCONFIG("Cppcheck.rul") + CL_EXPORTRUL + COMMON_CL_ARGS +}; + +static inline void updateMemStat(size_t *max_mem) { + memstat ms = getProcessUsedMemSize(); + if (*max_mem < ms.size) { + *max_mem = ms.size; + } +} + +int main(int argc, char* argv[]) { + int ret = EXIT_SUCCESS; + MAIN_BEGIN + + MainInit(argc, argv, "-"); + + if( !errorListFileName.empty() ){ + // Generating rul file from cppcheck error list + RuleConverter converter(rulConfig); + converter.process(configFileName, errorListFileName, groupsFileName); + converter.saveRulFile(rul_s); + } else { + loadStringListFromFile(fList, listOfFile); + if (listOfFile.empty()) { + WriteMsg::write(CMSG_NO_INPUT_FILE); + } + if (graphFileName.empty()) { + WriteMsg::write(CMSG_NO_OUTPUT_FILE); + clError(); + } + + // Converting cppcheck output + ResultConverter converter(limFileName, outputFileName, rul_s, rulConfig, exportRul, "", ""); + updateMemStat(&peakMemory); + for(list::iterator file = listOfFile.begin(); file != listOfFile.end(); ++file){ + if(pathFileExists(*file + ".err", false)) + converter.process(*file + ".err"); + else { + WriteMsg::write(CMSG_FILE_NOT_EXISTS, (*file + ".err").c_str()); + ret = EXIT_FAILURE; + } + } + updateMemStat(&peakMemory); + converter.aggregateWarnings(); + converter.saveResultGraph(graphFileName, false); + + updateMemStat(&peakMemory); + + } + + MAIN_END + + return ret; +} diff --git a/cl/DCF-CPP/CMakeLists.txt b/cl/DCF-CPP/CMakeLists.txt new file mode 100644 index 0000000..a559e33 --- /dev/null +++ b/cl/DCF-CPP/CMakeLists.txt @@ -0,0 +1,40 @@ +set (PROGRAM_NAME DuplicatedCodeFinder_cpp) + +set (SOURCES + src/main.cpp + src/dcm.cpp + src/AbstractFilter.cpp + src/CloneLengthFilter.cpp + src/ClonePositioned.cpp + src/CppSerializeAST.cpp + src/LanguageFactory.cpp + src/RepeatingLinesFilter.cpp + src/StatementFilter.cpp + + inc/messages.h + +) + + +if (CMAKE_SYSTEM_NAME STREQUAL Windows) + set (CLANG_PLATFORM_LIBRARIES + version + ) + +elseif (CMAKE_SYSTEM_NAME STREQUAL Linux) + set (CLANG_PLATFORM_LIBRARIES + pthread + z + tinfo + dl + ) +endif () + + +add_copy_custom_target(DCFRulCopyCPP ${CMAKE_CURRENT_SOURCE_DIR}/../DuplicatedCodeFinder/DCF.rul ${EXECUTABLE_OUTPUT_PATH}/DCF.rul) + +add_executable(${PROGRAM_NAME} ${SOURCES}) +add_dependencies(${PROGRAM_NAME} DCFRulCopyCPP clang ${COLUMBUS_GLOBAL_DEPENDENCY}) +target_link_libraries(${PROGRAM_NAME} clangsupport ${CLANG_COMMON_LIBRARIES} ${CLANG_PLATFORM_LIBRARIES} genealogy graphsupport lim2graph graph lim strtable common csi rul io ${COMMON_EXTERNAL_LIBRARIES}) +set_visual_studio_project_folder(${PROGRAM_NAME} FALSE) + diff --git a/cl/DCF-CPP/inc/AbstractFilter.h b/cl/DCF-CPP/inc/AbstractFilter.h new file mode 100644 index 0000000..d0ae443 --- /dev/null +++ b/cl/DCF-CPP/inc/AbstractFilter.h @@ -0,0 +1,51 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef __ABSTRACT_FILTER_H +#define __ABSTRACT_FILTER_H +#include "genealogy/inc/genealogy.h" + +namespace columbus { namespace dcf { + class DuplicatedCodeMiner; +} } + +class AbstractFilter { +private: + int currentValue; + +public: + AbstractFilter() ; + virtual ~AbstractFilter(){} + bool checkCloneClass(const columbus::genealogy::CloneClass& cc) { + currentValue++; + return isFiltered(cc); + } + virtual std::string getDebuggableName() { + return std::string("Filtering clones"); + } + int getMaxValue(); + int getValue() { + return currentValue; + } +protected: + virtual bool isFiltered(const columbus::genealogy::CloneClass& cc) = 0; +}; + +#endif diff --git a/javascript/cl/JSAN/src/ast/expression/assignmentProperty.js b/cl/DCF-CPP/inc/Aligner.h similarity index 84% rename from javascript/cl/JSAN/src/ast/expression/assignmentProperty.js rename to cl/DCF-CPP/inc/Aligner.h index e797287..899fe1d 100644 --- a/javascript/cl/JSAN/src/ast/expression/assignmentProperty.js +++ b/cl/DCF-CPP/inc/Aligner.h @@ -18,6 +18,16 @@ * limitations under the Licence. */ -module.exports = function (node, parent, firstVisit) { - //TODO: implement when supported -} \ No newline at end of file +#ifndef __ALIGNER_H +#define __ALIGNER_H + + +namespace Aligner { + enum AlignKind { + LineBoundary, + SyntaxBoundary + }; + +}; + +#endif diff --git a/cl/DCF-CPP/inc/CPPNamedVisitor.h b/cl/DCF-CPP/inc/CPPNamedVisitor.h new file mode 100644 index 0000000..afbe1e4 --- /dev/null +++ b/cl/DCF-CPP/inc/CPPNamedVisitor.h @@ -0,0 +1,206 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef DCF_CPP_NAMED_VISITOR_H +#define DCF_CPP_NAMED_VISITOR_H + +#include +#include +#include + +#include + + +using namespace std; + +class CPPNamedVisitor : public clang::ASTPrePostVisitor { + +private: + std::string repr; +public: + CPPNamedVisitor() : repr("") {} + operator std::string() { return repr; } + + /* visit DECL base */ + bool visitDecl(clang::Decl* decl) { + repr += std::string("#") + std::to_string(decl->getKind()); + + if(clang::isa(decl)){ + visitNamedDecl(static_cast(decl)); + } + + return true; + } + + void visitEndDecl(clang::Decl* decl) { + if(clang::isa(decl)){ + visitEndNamedDecl(static_cast(decl)); + } + visitEnd(); + } + + /* visit STMT base */ + bool visitStmt(clang::Stmt* stmt) { + repr += std::string("#") + std::to_string(stmt->getStmtClass()); + + if(clang::isa(stmt)){ + + visitFunctionCallExpression(static_cast(stmt)); + + }else if(clang::isa(stmt)){ + + visitStringLiteral(static_cast(stmt)); + + }else if(clang::isa(stmt)){ + + visitIntegerLiteral(static_cast(stmt)); + + } + + return true; + } + + + void visitEndStmt(clang::Stmt* stmt) { + if(clang::isa(stmt)){ + + visitEndFunctionCallExpression(static_cast(stmt)); + + }else if(clang::isa(stmt)){ + + visitEndStringLiteral(static_cast(stmt)); + + }else if(clang::isa(stmt)){ + + visitEndIntegerLiteral(static_cast(stmt)); + + } + + visitEnd(); + } + + //additional visit functions + + + void visitEnd(){ + repr += std::string("$"); + } + + void visitNamedDecl(clang::NamedDecl* named){ + if(named->getSourceRange().isInvalid()) + return; + + repr += std::string("#") + std::to_string(named->getKind()) + std::string("(") + named->getNameAsString(); + } + void visitEndNamedDecl(clang::NamedDecl* named){ + if(named->getSourceRange().isInvalid()) + return; + + repr += std::string(")"); + visitEnd(); + } + + + void visitFunctionCallExpression(clang::CallExpr* callExpr){ + if(callExpr->getSourceRange().isInvalid()) + return; + + repr += std::string("#") + std::to_string(callExpr->getStmtClass()); + const clang::FunctionDecl* refersTo = callExpr->getDirectCallee(); + if (refersTo) { + repr+=std::string("(")+refersTo->getNameAsString(); + } + } + void visitEndFunctionCallExpression(clang::CallExpr* callExpr){ + if(callExpr->getSourceRange().isInvalid()) + return; + + repr += std::string("#") + std::to_string(callExpr->getStmtClass()); + const clang::FunctionDecl* refersTo = callExpr->getDirectCallee(); + if (refersTo) { + repr+=std::string(")"); + } + visitEnd(); + } + + void visitStringLiteral(clang::StringLiteral* stringConst){ + if(stringConst->getSourceRange().isInvalid()) + return; + + repr += std::string("#") + std::to_string(stringConst->getStmtClass()); + + ///** debug **/ + // clang::PresumedLoc PLoc_start, PLoc_end; + // const clang::SourceManager& sm = AU->getASTContext().getSourceManager(); + // PLoc_start = sm.getPresumedLoc(stringConst->getLocStart()); + // PLoc_end = sm.getPresumedLoc(stringConst->getLocEnd()); + // cout << "\tString const at: " << PLoc_start.getFilename() << "[" << PLoc_start.getLine() << ":" << PLoc_start.getColumn() << " - " << PLoc_end.getLine() << ":" << PLoc_end.getColumn() << "]" << endl; + ///** debug end **/ + + clang::StringRef literalValue = stringConst->getBytes(); +// cout << "\t\tString const: " << literalValue.str() << endl; +// cout << "\t\tString data: " << literalValue.data() << endl; +// cout << "\t\tLength: " << stringConst->getLength() << endl; +// cout << "\t\tChar byte width: " << stringConst->getCharByteWidth() << endl; +// cout << "\t\tByte length: " << stringConst->getByteLength() << endl; + repr+=std::string("(") + literalValue.str(); + } + void visitEndStringLiteral(clang::StringLiteral* stringConst){ + if(stringConst->getSourceRange().isInvalid()) + return; + + repr+=std::string(")"); + visitEnd(); + } + + void visitIntegerLiteral(clang::IntegerLiteral* intConst){ + if(intConst->getSourceRange().isInvalid()) + return; + + repr += std::string("#") + std::to_string(intConst->getStmtClass()); + repr += std::string("(") + boost::lexical_cast(intConst->getValue().getSExtValue()); + } + void visitEndIntegerLiteral(clang::IntegerLiteral* intConst){ + if(intConst->getSourceRange().isInvalid()) + return; + + repr+=std::string(")"); + visitEnd(); + } + + void visitFloatingLiteral(clang::FloatingLiteral* floatConst){ + if(floatConst->getSourceRange().isInvalid()) + return; + + repr += std::string("#") + std::to_string(floatConst->getStmtClass()); + repr += std::string("(") + boost::lexical_cast(floatConst->getValue().convertToDouble()); + } + void visitEndFloatingLiteral(clang::FloatingLiteral* floatConst){ + if(floatConst->getSourceRange().isInvalid()) + return; + + repr+=std::string(")"); + visitEnd(); + } + +}; + + +#endif diff --git a/cl/DCF-CPP/inc/CloneLengthFilter.h b/cl/DCF-CPP/inc/CloneLengthFilter.h new file mode 100644 index 0000000..89720f8 --- /dev/null +++ b/cl/DCF-CPP/inc/CloneLengthFilter.h @@ -0,0 +1,42 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef __CLONE_LENGTH_FILER_H +#define __CLONE_LENGTH_FILER_H +#include "AbstractFilter.h" +#include "../inc/messages.h" + +class CloneLengthFilter: public AbstractFilter { +private: + + unsigned int length; + +public: + CloneLengthFilter(unsigned int length_): AbstractFilter(), length(length_) {}; + bool isFiltered(const columbus::genealogy::CloneClass& cc); + + std::string getDebuggableName() { + return std::string(CMSG_OS_RUNNING_CLONE_LENGTH_FILTER); + } +}; + + + +#endif diff --git a/cl/DCF-CPP/inc/CloneOccuranceFilter.h b/cl/DCF-CPP/inc/CloneOccuranceFilter.h new file mode 100644 index 0000000..1f37513 --- /dev/null +++ b/cl/DCF-CPP/inc/CloneOccuranceFilter.h @@ -0,0 +1,44 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef __CLONE_OCCURANCE_FILER_H +#define __CLONE_OCCURANCE_FILER_H +#include "AbstractFilter.h" +#include "../inc/messages.h" + +class CloneOccuranceFilter: public AbstractFilter { +private: + unsigned int occurance; + +public: + CloneOccuranceFilter(unsigned int _occurance) : AbstractFilter(), occurance(_occurance) {}; + bool isFiltered(const columbus::genealogy::CloneClass& cc) { + if(cc.getInstances() < occurance) return true; + return false; + } + + std::string getDebuggableName() { + return std::string(CMSG_OS_RUNNING_OCCURANCE_FILTER); + } +}; + + + +#endif diff --git a/cl/DCF-CPP/inc/ClonePositioned.h b/cl/DCF-CPP/inc/ClonePositioned.h new file mode 100644 index 0000000..ffbabb8 --- /dev/null +++ b/cl/DCF-CPP/inc/ClonePositioned.h @@ -0,0 +1,122 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef __CLONE_POSITIONED_H +#define __CLONE_POSITIONED_H +/** + * \brief This class is store the extract of asg node contain the position data of asg node. + */ + +#include +#include +#include + +class ASTNodeInfo +{ +private: + static columbus::StrTable paths; + + columbus::Key path; + unsigned int line; + unsigned int col; + unsigned int endLine; + unsigned int endCol; + + columbus::NodeId nodeId; + columbus::NodeId limNodeId; + columbus::NodeId translationUnitId; + columbus::Key TUPathKey; + columbus::NodeId limComponentId; + std::vector* extraLines; + +public: + + + ASTNodeInfo(const std::string& _path, + unsigned int _line, + unsigned int _col, + unsigned int _endLine, + unsigned int _endCol, + columbus::NodeId _nodeId, + columbus::NodeId limNodeId, + columbus::NodeId translationUnitId, + const std::string& _tuPath, + columbus::NodeId limComponentId) + : path(paths.set(_path)) + , line (_line) + , col (_col) + , endLine(_endLine) + , endCol(_endCol) + , nodeId(_nodeId) + , limNodeId(limNodeId) + , translationUnitId(translationUnitId) + , TUPathKey(paths.set(_tuPath)) + , limComponentId(limComponentId) + , extraLines (nullptr) + { + + } + + ~ASTNodeInfo() + { + delete extraLines; + } + + ASTNodeInfo& operator=(const ASTNodeInfo&) = delete; + + static const std::string& getStringPath(columbus::Key path) { return paths.get(path); } + static columbus::Key getPathKey(const std::string& path) { return paths.set(path); } + + columbus::Key getPath() const { return path; } + const std::string& getStringPath() const { return paths.get(path); } + unsigned int getLine() const { return line; } + unsigned int getCol() const { return col; } + unsigned int getEndLine() const { return endLine; } + unsigned int getEndCol() const { return endCol; } + int getPathsSize() const { return paths.getNumberOfBuckets(); } + + columbus::NodeId getId() const { return nodeId; } + columbus::NodeId getLimNodeId() const { return limNodeId; } + columbus::NodeId getTranslationUnitId() const { return translationUnitId; } + columbus::Key getTUPath() const { return TUPathKey; } + const std::string& getStringTUPath() const { return paths.get(TUPathKey); } + columbus::NodeId getLimComponentId() const { return limComponentId; } + void setLimNodeId(columbus::NodeId nId) { limNodeId = nId; } + void setLimComponentId(columbus::NodeId nId) { limComponentId = nId; } + + void addLine(int line) + { + if (extraLines == nullptr) + extraLines = new std::vector(); + + if (extraLines != nullptr) + extraLines->push_back(line); + } + + std::vector* getExtraLines() const + { + return extraLines; + } + + + void dump(); +}; + +#endif diff --git a/cl/DCF-CPP/inc/Config.h b/cl/DCF-CPP/inc/Config.h new file mode 100644 index 0000000..7616ec3 --- /dev/null +++ b/cl/DCF-CPP/inc/Config.h @@ -0,0 +1,125 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _CONFIG_H +#define _CONFIG_H + +#define PROGRAM_NAME "DuplicatedCodeFinder" +#define EXECUTABLE_NAME "DuplicatedCodeFinder" + + +#define TOOL_NAME "Columbus Clone Extractor (v1.1)" + +#define DCM_RELAXATIONS "dcmRelaxations" +#define DCM_MATCH "dcmMatch" +#define DCM_LOWMEMORY "dcmLowMemoryMode" +#define DCM_OUT "dcmOutput" +#define DCM_STDOUT "dcmStdout" +#define DCM_FUNCTION_BLOCK_ONLY "dcmFunctionBlocksOnly" +#define DCM_MAP_FILE_NAME "dcmMapFileName" +#define DCM_MAP_SIZE "dcmMapSize" +#define DCM_ALGORITHM "dcmAlgorithm" +#define DCM_LINES "dcmLines" + + +#define LIM_FILTER_FILE_EXTENSION ".flim" +#define FILTER_FILE_EXTENSION_W L".fcsi" + +#include +#include +#include + +struct Config { + + Config() + : minLines (10) + , minAsgNodes (35) + , minOccur (2) + , metrics (false) + , lp (false) + , inputFile (false) + , singleAsgRoot (true) + , ofc (false) + , patternMaxSingleLength(10) + , patternMinFullLength(100) + , exportRul(false) + , statementFilter(true) + , smallGenealogy(true) + , maxCCSize(0) + { + memset(&stat,0,sizeof(stat)); + } + + unsigned int minLines; ///< minimum lines in clone + unsigned int minAsgNodes; ///< minimum asg nodes at clone + unsigned int minOccur; ///< minimum clone occurrence + std::string genealogyFilename; ///< name of the genealogy instance file + bool metrics; ///< calculate metrics + bool lp; ///< lower path + bool inputFile; + bool singleAsgRoot; + bool ofc; ///< only function clones + unsigned int patternMaxSingleLength;///< maximal length of a single pattern + unsigned int patternMinFullLength; ///< minimal length of the full repeating pattern series + std::string dcFout; + std::string fList; ///< list of the input files + std::string blockPaths; ///< list of the paths which should be blocked + std::string rul_str; ///< location of the .rul file + std::string rulConfig; ///< rule configuration + std::string dcout; ///< name of the output file + std::list files; ///< list of the input files + std::list bpaths; + std::string graphFilename; + std::string limFileName; + bool exportRul; + std::string systemName; + std::string systemVersion; + std::string filterfile; + + struct { + uint64_t memory_peak; + uint64_t asgSerializationTime; + uint64_t filterTime; + uint64_t cloneFindTime; + uint64_t cloneClassFilterTime; + uint64_t calculateMetricsTime; + uint64_t finalizeTime; + uint64_t buildCloneTreeTime; + uint64_t evolutionMappingTime; + + unsigned int serializedASGLength; + unsigned int serializedASGLengthFiltered; + unsigned int numOfFoundsuffixInstances; + unsigned int numOfpotInstances; + unsigned int numOfFoundsuffixClass; + unsigned int numberOfInstancesInTheLastSystem; + unsigned int numberOfTrivialPairs; + unsigned int totalASTNodeNumber; + } stat; + + bool statementFilter; + bool smallGenealogy; ///< keep the string attributes of the last system only in the genealogy output + std::string xmlDumpFile; + int maxCCSize; ///< muber of maximum allowed clone instance in one clone class +}; + +extern Config config; + +#endif diff --git a/cl/DCF-CPP/inc/CppSerializeAST.h b/cl/DCF-CPP/inc/CppSerializeAST.h new file mode 100644 index 0000000..e03de19 --- /dev/null +++ b/cl/DCF-CPP/inc/CppSerializeAST.h @@ -0,0 +1,226 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _DCF_CPP_SERIALIZE_AST_H +#define _DCF_CPP_SERIALIZE_AST_H + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace columbus { class DuplicatedCodeMiner; } + +#include "ClonePositioned.h" +#include "Types.h" +#include +#include +#include +#include + + +enum NodeType +{ + Statement = 0x00010000, + Declaration = 0x00020000 +}; + +enum NodeEndType +{ + NodeStart = 0x00000000, + NodeEnd = 0x01000000 +}; + +enum NodeBOType +{ + LogicalBinaryOperator = 0x02000000 +}; + +enum NodeMask +{ + NodeKindMask = 0x0000FFFF, + NodeTypeMask = 0x00FF0000, + NodeEndMask = 0x01000000, + LogicalBOMask = 0x02000000, + SeparatorMask = 0x80000000 +}; + +class CppCloneVisitor; + + +struct LocalSerializationData +{ + std::map ASTNodeReferenceMap; + std::map ASTNodeFileIDMap; // This is collected for the references only! + std::map> ASTNodeExtraLineMap; // Extra info for calculatig logical lines +}; + +class ASTSerializerConsumer : public clang::ASTConsumer +{ + public: + ASTSerializerConsumer(columbus::SerializationData& serializationData, CppCloneVisitor* ccVitor); + virtual void HandleTranslationUnit(clang::ASTContext &context) override; + + private: + void addSeparator(); + + private: + columbus::SerializationData& serializationData; + CppCloneVisitor* ccVitor; + + LocalSerializationData localSerializationData; + std::string prevPath; + unsigned int prevLine; + std::set* filter; + std::ostream *filterLogStream; +}; + +class ASTSerializerVisitor : public clang::RecursiveASTVisitor +{ + public: + + struct NodeInfo + { + void* nodePtr; + clang::FileID pathID; + std::uint32_t nodeKind; + std::uint32_t nodeId; + std::uint32_t line_start; + std::uint32_t line_end; + std::uint16_t column_start; + std::uint16_t column_end; + }; + + using NodeList = std::vector; + + ASTSerializerVisitor(clang::ASTContext &context, bool post, NodeList& nodes, CppCloneVisitor* ccVitor, LocalSerializationData& localSerializationData); + + bool VisitStmt(clang::Stmt *s); + bool VisitDecl(clang::Decl *d); + bool shouldTraversePostOrder() const; + + clang::RecordDecl* getReferencedRecordDecl(const clang::Type* typePtr) const; + void addToRefernceMaps(clang::Decl* decl, void *node); + + template + void fillLocationInfo(T* node, NodeInfo& nodeInfo); + + void addExtraLineInfo(void* node, const clang::SourceLocation& sourceLocation); + + static NodeList merge(const NodeList& pre, const NodeList& post); + static void dumpNodeInfo(const NodeInfo& nodeInfo, clang::ASTContext *context); + static void dumpNodeList(const NodeList& nodes, clang::ASTContext *context); + template + static void dumpLineInfo(clang::ASTContext *context, T* node, int nodeKind); + + + private: + clang::ASTContext &context; + bool post; + NodeList& nodes; + CppCloneVisitor* ccVitor; + LocalSerializationData &localSerializationData; +}; + +class SerializeAction : public clang::ASTFrontendAction +{ + public: + SerializeAction(columbus::SerializationData& serializationData, CppCloneVisitor* ccVitor); + virtual std::unique_ptr CreateASTConsumer(clang::CompilerInstance &Compiler, llvm::StringRef InFile); + + private: + columbus::SerializationData& serializationData; + CppCloneVisitor* ccVitor; +}; + + + +class CppCloneVisitor +{ +private: + columbus::LimOrigin& limOrigin; + columbus::lim::asg::Factory* limFactory; + + std::set* filter; + int visitedNodes; + + const int uniqueValue; + const int decDepthSign; + int separatorCounter; + + std::string prevPath; + std::map >* fileNamesByComponent; + std::map>* tuPathToCompAndTuId; + + std::stack currentLimNode; + columbus::NodeId currentLimComponent; + columbus::NodeId currentTUId; + std::string currentTUPath; + std::ostream *filterLogStream; + + bool parseLimNodeId( const ASTNodeInfo* n, columbus::NodeId& limNodeID ); + columbus::NodeId getLimCompilationIdByName( const std::string& name ); + +public: + CppCloneVisitor(columbus::LimOrigin& limOrigin, columbus::lim::asg::Factory* limFactory); + + void serializeComponent(const std::list& compilationUnits, columbus::SerializationData& serializationData); + std::unique_ptr newSerializeActionFactory(columbus::SerializationData& serializationData); + + void setFilter(std::set& filter); + std::set* getFilter(); + void clearFilter(); + + bool evoluteLimNode( const ASTNodeInfo* n, bool end ); + void updateLimNodeStack(columbus::NodeId astNodeId, bool end); + columbus::NodeId getCurrentLimNode(); + void setCurrentLimComponent(columbus::NodeId id); + void setCurrentTranslationUnitId(columbus::NodeId id); + columbus::NodeId getCurrentLimComponent(); + columbus::NodeId getCurrentTranslationUnitId(); + const std::string& getCurrentTranslationUnitPath() const; + int getVisitedNodesNumber(); + void incVisitedNodes(); + void decVisitedNodes(); + void resetVisitedNodesNumber(); + bool isSepDecDepthSign(int s); + int getUniqueValue(); + int getDecDepthSign(); + int getSeparator(); + + void setFileNamesByComponent(std::map >* val) { fileNamesByComponent = val; } + void setTuPathToCompAndTuId( std::map>* val) { tuPathToCompAndTuId = val; } + bool isFilteredInLim(columbus::NodeId limId); + + const columbus::lim::asg::Factory& getLimFactory(); + void assignSrcFileToComponenet( const std::string &lPath, columbus::NodeId currentLimComponent ); + std::string& getPrevPath(){ return prevPath; } + void setPrevPath(const std::string& val){ prevPath = val; } + const std::map >* getFileNamesByComponent(){ return fileNamesByComponent; } + const std::map>* getTuPathToCompAndTuId(){ return tuPathToCompAndTuId; } + void setFilterLogStream(std::ostream *out); + std::ostream *getFilterLogStream() const; +}; + +#endif diff --git a/cl/DCF-CPP/inc/DistanceVisitor.h b/cl/DCF-CPP/inc/DistanceVisitor.h new file mode 100644 index 0000000..c5488a0 --- /dev/null +++ b/cl/DCF-CPP/inc/DistanceVisitor.h @@ -0,0 +1,117 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef DISTANCEVISITOR_H_ +#define DISTANCEVISITOR_H_ + + +#include + +class DistanceVisitor : public clang::ASTPrePostVisitor{ + private: + + void* child; + + // the number of AST nodes from the beginning of the first named ancestor node to the beginning of the instance + unsigned int l1; + // the length of the instance (measured by the number of AST nodes) + unsigned int l2; + //the number of nodes from the end of the instance to the end of the first named ancestor node + unsigned int l3; + + short state; + + public: + DistanceVisitor(void* _child) : child(_child) ,l1(0), l2(0), l3(0), state(0) { }; + unsigned int getL1() const { + return l1; + } + unsigned int getL2() const { + return l2; + } + unsigned int getL3() const { + return l3; + } + + bool visitDecl(clang::Decl* decl) { + if(decl == child && state == 0){ + state = 1; + l2++; + } else if (state==0) { + l1++; + } else if (state==1) { + l2++; + } else if (state==2) { + l3++; + } + + return true; + } + + void visitEndDecl(clang::Decl* decl) { + if (decl == child && state == 1) { + state=2; + } + } + + bool visitStmt(clang::Stmt* stmt) { + if(stmt == child && state == 0){ + state = 1; + l2++; + } else if (state==0) { + l1++; + } else if (state==1) { + l2++; + } else if (state==2) { + l3++; + } + + return true; + } + void visitEndStmt(clang::Stmt* stmt) { + if (stmt == child && state == 1) { + state=2; + } + } + + bool visitType(clang::Type* type) { + if(type == child && state == 0){ + state = 1; + l2++; + } else if (state==0) { + l1++; + } else if (state==1) { + l2++; + } else if (state==2) { + l3++; + } + + return true; + } + void visitEndType(clang::Type* type) { + if (type == child && state == 1) { + state=2; + } + } + +}; + + +#endif /* DISTANCEVISITOR_H_ */ diff --git a/cl/DCF-CPP/inc/Interval.h b/cl/DCF-CPP/inc/Interval.h new file mode 100644 index 0000000..ce825d8 --- /dev/null +++ b/cl/DCF-CPP/inc/Interval.h @@ -0,0 +1,82 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef __INTERVAL_H +#define __INTERVAL_H + +#include + +struct Interval { + unsigned int a; + unsigned int b; + + mutable std::vector* intervals; + + Interval(const Interval& object) + : a(object.a) + , b(object.b) + , intervals(object.intervals) + { + object.intervals = NULL; + //TODO write a safer solution like this. : + /*if (object.intervals != NULL) { + intervals = new std::set(*object.intervals); + } + but the current solution is faster :-) */ + } + + const Interval& operator=(const Interval&); + + Interval(unsigned int _a, unsigned int _b) : a(_a), b(_b), intervals(NULL) { } + + bool operator<=(const Interval& I) { + /** + * This realtion is actually the contains relation + */ + return (a>=I.a && b<=I.b); + } + bool operator==(const Interval& I) { + return (a==I.a && b==I.b); + } + bool operator<(const Interval& I) { + /* + partial ordering is defined by means of the lhs of the interval + */ + return (a(*intervals); + else + I.intervals = NULL; + return I; + } +}; + +inline bool operator<(const Interval& I1, const Interval& I2) { + return I1.a>I2.a; +} +#endif diff --git a/cl/DCF-CPP/inc/LanguageFactory.h b/cl/DCF-CPP/inc/LanguageFactory.h new file mode 100644 index 0000000..ca580e4 --- /dev/null +++ b/cl/DCF-CPP/inc/LanguageFactory.h @@ -0,0 +1,65 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef LANGUAGEFACTORY_H_ +#define LANGUAGEFACTORY_H_ + +#include +#include +#include + +#include +#include + +#include + +namespace columbus { + +class LanguageFactory { + +protected: + bool loaded; + std::map limComponentNameFileNameMap; + std::map hashCodes; + +public: + LanguageFactory(); + virtual ~LanguageFactory(); + + const std::map& getLimComponentNameFileNameMap() const; +public: + + void load(columbus::genealogy::System& system, bool deleteFiltered=false) ; + std::string getFileNameByComponentId(const std::string& id); + bool isLoaded() const { + return loaded; + } + + + /** + * @brief This function is fill the limComponentNameFileNameMap data structure. + * @parameter listOfInputFile the list of string with the language asg names. + */ + void fillComponentList (std::list listOfInputFile); + +}; + +} +#endif /* LANGUAGEFACTORY_H_ */ diff --git a/cl/DCF-CPP/inc/RepeatingLinesFilter.h b/cl/DCF-CPP/inc/RepeatingLinesFilter.h new file mode 100644 index 0000000..61fd4d8 --- /dev/null +++ b/cl/DCF-CPP/inc/RepeatingLinesFilter.h @@ -0,0 +1,46 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _REPEATING_LINES_FILTER +#define _REPEATING_LINES_FILTER + +#include "AbstractFilter.h" +#include "messages.h" + +namespace columbus +{ + class DuplicatedCodeMiner; +} + +class RepeatingLinesFilter: public AbstractFilter { +private: + const columbus::DuplicatedCodeMiner& dcm; + +public: + RepeatingLinesFilter(columbus::DuplicatedCodeMiner& dcm) : AbstractFilter(), dcm(dcm) {}; + bool isFiltered(const columbus::genealogy::CloneClass& ccre); + + std::string getDebuggableName() { + return std::string(CMSG_OS_FILTERING_CLONES_WITH_REPEATING_LINES); + } + +}; + +#endif diff --git a/cl/DCF-CPP/inc/StatementFilter.h b/cl/DCF-CPP/inc/StatementFilter.h new file mode 100644 index 0000000..f74cbba --- /dev/null +++ b/cl/DCF-CPP/inc/StatementFilter.h @@ -0,0 +1,39 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _DCF_STMTFIL_H_ +#define _DCF_STMTFIL_H_ + +#include "AbstractFilter.h" + +class StatementFilter: public AbstractFilter { +private: + const columbus::DuplicatedCodeMiner& dcm; +public: + StatementFilter(columbus::DuplicatedCodeMiner& dcm) : AbstractFilter(), dcm(dcm) {}; + bool isFiltered(const columbus::genealogy::CloneClass& cc); + + std::string getDebuggableName() { + return std::string("StatementFilter"); + } + +}; + +#endif diff --git a/cl/DCF-CPP/inc/Types.h b/cl/DCF-CPP/inc/Types.h new file mode 100644 index 0000000..1bbf9db --- /dev/null +++ b/cl/DCF-CPP/inc/Types.h @@ -0,0 +1,95 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _DCF_TYPES_H_ +#define _DCF_TYPES_H_ + +#include +#include +#include +#include + + +namespace columbus +{ + +typedef std::map> ASTNodeReferenceMap; +typedef std::map>> ASTNodeInverseReferenceMap; +typedef std::map> ASTNodeReferencePathMap; + +struct LineIdentifier { + + LineIdentifier() + : path(0) + , line(0) + { + } + + LineIdentifier (const LineIdentifier & p) + : path(p.path) + , line(p.line) + { + } + + LineIdentifier (columbus::Key path, int line) + : path(path) + , line(line) + { + } + + bool operator<(const LineIdentifier& second) const + { + if (line != second.line) + return line < second.line; + + return path < second.path; + } + + //This is the key of the path string (in the lim asg string table) + columbus::Key path; + int line; +}; + + +struct SerializationData +{ + // Vector containing the sequence of node kinds + std::vector nodeKindSequence; + + // Vector containing sequence of additional information about each node + std::vector nodeInfoSequence; + + // Node references in each AST + ASTNodeReferenceMap referencesMap; + + // Inverse of the references + ASTNodeInverseReferenceMap inverseReferencesMap; + + // Path info for all the nodes stored in the reference maps for CE metrics + ASTNodeReferencePathMap nodeReferencePathMap; + + + std::set visitedLines; +}; + +} + + +#endif diff --git a/cl/DCF-CPP/inc/dcm.h b/cl/DCF-CPP/inc/dcm.h new file mode 100644 index 0000000..d6f504d --- /dev/null +++ b/cl/DCF-CPP/inc/dcm.h @@ -0,0 +1,828 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef __DCM_H +#define __DCM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "Config.h" +#include "ClonePositioned.h" +#include "Interval.h" +#include "CppSerializeAST.h" +#include "Aligner.h" +#include "LanguageFactory.h" +#include "Types.h" + + +//the original sequitur algorithm is used! + +#define SEQUITUR_ORIG +#define SYNTAX_ALIGN + +using namespace std; + +class AbstractFilter; +class CppCloneVisitor; + +namespace columbus { + +enum DCFState { + DCFS_NORMAL, + DCFS_COVERED, + DCFS_FILTERED +}; + +/** + *\brief This map contains which clone instances' IDs and AST paths. + */ +extern std::map ciIdToAST; + + +struct sortCloneInstancesByComponentId { + inline bool operator() (genealogy::CloneInstance* struct1, genealogy::CloneInstance* struct2) { + return (struct1->getComponent()->getId() < struct2->getComponent()->getId()); + } +}; + + +void dump(const genealogy::CloneInstance& ci, std::ostream& out); + +/** + * \internal + * \brief update the memory usage statistics + */ +void updateMemoryStat(Config &config, const char* msg = nullptr); + + +class DuplicatedCodeMiner { +private: + //the not implemented constructors it may be deny the copy of object + DuplicatedCodeMiner(const DuplicatedCodeMiner&); + const DuplicatedCodeMiner& operator=(const DuplicatedCodeMiner&); +public: + /** + * \brief constructor + * \param blockedPaths this path is not serialized. + * \param genealogy [in] the genealogy file name + * \param metOut [in] prepare to metrics/graph out + * \param rulHandler [in] handler for rul configuration file + * \param files [in] list of + * \param limFile the name of the lim file + * + */ + DuplicatedCodeMiner(Config& config, columbus::rul::RulHandler* rulHandler); + + /** + * \brief destructor + */ + virtual ~DuplicatedCodeMiner(); + + int getCloneClassNum() const; + int getCloneInstanceNum()const; + void saveGenealogy(); + + void setStatementFilter(bool val); + + int getNodeKindSequenceSize(); + +protected: + bool statementFilter; + + // genealogy file name + Config& config; + // string table for genealogy factory + columbus::RefDistributorStrTable* strTable; + // genealogy factory + columbus::genealogy::Factory* genealogyFact; + // the lim factory + columbus::lim::asg::Factory* limFact; + std::set visitedLimNodes; // TODO: remove? + std::map > fileNamesByComponent; // TODO: remove? + + struct ComponentMetrics + { + double CR; + double CEE; + }; + + std::map componentMetrics; + + /** + * \brief Matching AST path to < component id, translation unit id > + */ + std::map> tuPathToCompAndTuId; + + + std::map serializedAsgNodeNumberByComponenet; + LimOrigin limOrigin; + + std::map > limNodeCloneInstanceMap; // NodeId of the clone instance in the genealogy ASG -> set of NodeIds of source code elements in the LIM ASG + std::map > limComponentCloneInstanceMap; // NodeId of the clone instance in the genealogy ASG -> set of NodeIds of component nodes in the LIM ASG + + // Temporal storages to set string attributes after the filtering stage not to fill the stringtable as they are not removed during the node deletion. + std::map cloneClassFingerprintMap; // NodeId of the clone class in the genealogy ASG -> Fingerprint of the class. + std::map cloneInstanceRootNodesMap; // NodeId of the clone instance in the genealogy ASG -> Root nodes of the clone instance. + + //this map is conatin the version of lim node + columbus::lim::asg::MangledNameKey2LimId nameMap; + + // the currently builded system + columbus::genealogy::System* currentSystem; + // the previous system in the genealogy file + const columbus::genealogy::System* lastSystem; + + unsigned int currentSystemMaxNDC; + // rul handler + columbus::rul::RulHandler* rulHandler; + // output graph + columbus::graph::Graph graph; + + // factory manager for asg-s + LanguageFactory currentFactory; + + // graph indexer + columbus::graphsupport::GraphRangeIndexer* indexer; + + // information collected during serialization of the ASTs + SerializationData serializationData; + + //lim node -> + std::map> lineMetrics; + + //compilation unit -> Clone logical lines of code + std::map astCloneLogicalLines; + + // map for the node and its connected nodes with NDCs + //NodeEmbeddednessVisitorBase::ConectedEdgesMap conectedEdgesMap; + + struct SerializedAsg { + std::vector nodeKindSequence; + std::vector nodeInfoSequence; + std::map positionCache; + int decDepthSign; + }; + + struct PotentialCloneInstance { + unsigned startPosition; + std::shared_ptr I; + PotentialCloneInstance(unsigned startPosition, std::shared_ptr I) : startPosition(startPosition), I(I) { } + + bool operator<(const PotentialCloneInstance& pci) const { + return startPosition + I->a < pci.startPosition + pci.I->a; + } + + PotentialCloneInstance(const PotentialCloneInstance& pci) : startPosition(pci.startPosition), I(pci.I) { } + + void dump() + { + printf("PCI:%u I.a:%u I.b:%u\n", startPosition, I->a, I->b); + if (I->intervals != nullptr) + { + printf("Intervals:"); + for (auto& i: *I->intervals) + printf("%u, ", i); + printf("\n"); + } + + } + private: + const PotentialCloneInstance& operator=(const PotentialCloneInstance& pci); // Intentionally not implemented! + + }; + + // maps a clone class to the set of its potential clone instances + typedef std::map > CloneClassPotentialCloneInstanceMap; + + // the map of genealogy CloneInstance location for asg + std::map serializedAsgMap; + + + + // instead of MD% sum using the sequence positions only + std::map cloneClassMap; + + // clone visitor + CppCloneVisitor* theCloneVisitor; + ostream* filterOut; + + // number of trivial pairs at evolution mapping + unsigned int trivial_pairs; + bool dumpGraphml; + + // clone instance position at serialized asg + std::map positions; + + // clone classes length + std::map lengths; + + std::map > filteredNodes; + std::set coveredLines; + std::map > coveredNodes; + + common::Cache nodeDepthCache; + +protected: + + void dumpNodeIdSequence(const std::string filename); + void dumpNodeKindSequence(const std::string filename); + void dumpCloneInstanceInformation(); + + /** + * \internal + * \brief detect clones in serialized asg + * \param coveredNodes [out] calculate the covered nodes in asg-s + * \param needToSkip [inout] skipped paths + * \param overlap [in] allow overlapped clone instances + */ + void detectClones(std::map >& coveredNodes, std::set& needToSkip); + + bool isFilteredCC(const genealogy::CloneClass& cc); + + /** + * \internal + * \brief return true, if metric is turned on in rul file + * \return true if metric calculation is needed, otherwise return false + */ + bool getIsNeeded(const std::string& id) const; + + /** + * \internal + * \brief add metric and summarize along relType edges if it is needed + * \param name [in] the metric name + * \param relType [in] the edge type + * \param node [in] node in output graph + * \param value [in] the metric value + * \param sumUp [in] summarize metric to parents + */ + void addValue(const string& name, const std::list& relType, const columbus::graph::Node& node, int value, bool sumUp); + + /** + * \internal + * \brief get node parents + * \param node [in] the start node + * \param edgeType [in] get parents along edgetype edges + * \param nodes [out] parents of the node + */ + void getParent(const columbus::graph::Node& node, const std::list& relType, std::list& nodes); + + /** + * \internal + * \brief get node parents and parenets' parenets too + * \param node [in] the start node + * \param edgeType [in] get parents along edgetype edges + * \param nodes [out] parents of the node + */ + void getParentTransitve(const columbus::graph::Node& node, const std::list& relType, std::set& nodes); + + /** + * \internal + * \brief find node in graph by source code position + * \param graph [inout] the output graph + * \param path [in] node path + * \param line [in] line + * \param col [in] column + * \param endLine [in] end line + * \param endCol [in] end column + * \return node at specified position + */ + columbus::graph::Node findNodeByRange(columbus::graph::Graph& graph, const string& path, int line, int col, int endLine, int endCol); + + + /** + * \internal + * \brief build clone tree into output graph + */ + void buildBaseCloneTree(); + + void incCSOnPrevCloneClass(columbus::genealogy::CloneInstance &ci); + + void collectContainerFiles(const lim::asg::logical::Package &package, std::set &fileNames); + + /** + * \internal + * \brief save component and its parent components + * \param componentsOfTheClass [out] the output set of (parent) components + * \param currentComp [in] the current component to be added + */ + void addParentComponents(std::set &componentsOfTheClass, NodeId currentComp); + + /** + * \internal + * \brief compute finger print from serialized asg + * \param pos [in] clone start position in asg + * \param length [in] clone length + * \return the clone class finger print + */ + std::string computeCloneClassCode(unsigned int pos, unsigned int length); + + /** + * \internal + * \brief align clone class begin and end to positioned nodes + * \param alignKind [in] the alignment kind + * \param suffixCl [in] clone class from suffix array + */ + void alignCloneClass(Aligner::AlignKind alignKind, const suffix_array::SuffixArray::CloneClass& suffixCl, CloneClassPotentialCloneInstanceMap& potentialCloneInstances); + + /** + * \internal + * \brief create clone class by position in serialized asg and length + * \param position [in] the start position in serialized asg + * \param length [in] clone class length + * \param isNewClass [out] return true, if class instance is created, otherwise return false + * \return clone class for specified position and length + */ + genealogy::CloneClass* createCloneClass(unsigned int position, unsigned int length, bool& isNewClass); + + /** + * \internal + * \brief create clone instance by position and length + * \param position [in] the start position + * \param length [in] the instance length + * \param parent [in] instance parent + * \return created clone instance + */ + genealogy::CloneInstance* createCloneInstance(unsigned int position, unsigned int length, unsigned int intervalStart, std::vector* intervals, genealogy::CloneClass& parent); + + /** + * \internal + * \brief find clone instance in clone class + * \param position [in] clone instance position + * \param cc [in] clone class + * \return true, if clone instance founded, otherwise return false + */ + bool containsInstanceAtPositon(unsigned int position, const genealogy::CloneClass& cc); + + /** + * \internal + * \breif return first node position at specified interval + * \param from [in] interval begin + * \param to [in] interval end + * \return the node position + */ + const ASTNodeInfo* getFirstNode(unsigned int from, unsigned int to) const; + + /** + * \internal + * \breif return end node position at specified interval + * \param from [in] interval begin + * \param to [in] interval end + * \return the node position + */ + const ASTNodeInfo* getEndNode(unsigned int from, unsigned int to) const; + + /** + * \internal + * \brief compute nodes covered by clones + */ + void computeCoveredNodes(); + + /** + * \internal + * \brief depth of the given node in the logical tree if it is a sourcecode element or in the component tree if it is a component node + * \return the depth of the given LIM node + */ + int getLimNodeDepth(NodeId); + + + /** + * \internal + * \brief evolution mapping of clones + * \brief systemRef [inout] current system + * \brief genealogyBase [in] the project + */ + void evolutionMapping(columbus::genealogy::System& systemRef, columbus::genealogy::Project& genealogyBase); + + /** + * \internal + * \brief set the unique name of clone classes/instances and clone smells + */ + void setClonesUniqueNameAndCloneSmells(); + + /** + * \internal + * \brief generate the unique name for genealogy node + */ + std::string getGraphNameOfGenelogyNode(const columbus::genealogy::Base& genealogyBase); + + /** + * \internal + * \brief initialize genealogy graph + * \param errorAtLoad [out] true if genealogy file load failed + * \return the created/loaded project + */ + columbus::genealogy::Project& initGenealogy(bool& errorAtLoad); + + /** + * \internal + * \brief initialize/load lim graph + * \return true if succeeded + */ + bool initLim(); + + /** + * \internal + * \brief createSystem node in the genelogy factory + * \return the created node + */ + columbus::genealogy::System* createSystem(); + + /** + * \internal + * \brief compute coverage for asg-s and build output graph + * \param cv2 [in] coverage visitor + * \param coveredNodes [in] the covered nodes + */ + //void computeCoverage(COVERAGE_VISITOR* cv2, std::map >& coveredNodes); + + /** + * \internal + * \brief create backup form components to 'backup' directory + * \param backup [out] the output directory + */ + void createBackup(const std::string& backup); + + /** + * \internal + * \brief use pattern filter and reserialize the asg. + */ + void patternFilter(); + + /** + * \internal + * \brief serialize all the given asg-s. + * \param createComponent create new component for the genealogy + */ + + int serializeAsg(bool createComponent); + + std::vector getInstanceIds(const genealogy::CloneInstance&); + + /** + * \internal + * \brief It calculates clone complexity for clones. + */ + void calculateCCO(); + + /** + * \internal + * \brief It calculates CCL metrics. + */ + void calculateCCL(); + + /** + * \internal + * \brief It calculates CCL metrics. + */ + void calculateCC(); + + /** + * \internal + * \brief It calculates CI metrics. + */ + void calculateCI(); + + /** + * \internal + * \brief It calculates CLC and LLDC metrics. + */ + void calculateCLC_LDC(); + + /** + * \internal + * \brief It calculates CLLC and LLDC metrics. + */ + void calculateCLLC_LLDC(); + + /** + * \internal + * @brief It calculates CLLOC metrics + */ + void calculateCLLOC(); + + /** + * \internal + * @brief It calculates NCR metrics + */ + void calculateNCR(); + + /** + * \internal + * @brief It calculates CE metrics + */ + void calculateCE(); + + /** + * \internal + * @brief It calculates CE metrics + */ + void calculateCEE(); + + /** + * \internal + * @brief It calculates CEG metrics + */ + void calculateCEG(); + + /** + * \internal + * @brief It calculates CR metrics + */ + void calculateCR(); + + /** + * \internal + * @brief It calculates CA metrics + */ + void calculateCA(); + + /** + * \internal + * @brief It calculates CV metrics + */ + void calculateCV(); + + + /** + * \internal + * \brief It calculates the clone metrics + */ + void calculateMetrics(); + + /** + * \internal + * \brief It calculates the evolution dependent clone metrics + */ + void calculateEvolutionDependentMetrics(); + + /** + * \internal + * \brief It adds the clone metrics with default values for nodes not related + * to any clone instances. + */ + void addDefaultMetricsForTheNodes(); + + /** + * \internal + * \brief It gives back CLLC metric + * \param limNodeId [in] The LIM node identifier for which CLLC is calculated + * \param codeLLOC [out] The LLOC metric of the code fragment which represented by LIM node. + * \param cloneLLOC [out] The sum of those clones' LLOC which are contained by the give LIM node. + * \return CLLC value + */ + float getCLLC(NodeId limNodeId, int& codeLLOC, int& cloneLLOC); + + /** + * \internal + * \brief + * \param astWithNodeIdMaps [in] + * \param cloneRootsByElements [in] + */ + void fillLineMetrics(const columbus::ASTWithNodeIDMaps& astWithNodeIdMaps, const std::map>& cloneRootsByElements); + + /** + * \internal + * \brief Calculates CLLC metric and stores it into lineMetrics map. + */ + void computeCLLC(); + + /** + * \internal + * \brief This method fills the parents set recursively of the given lim node. + */ + void getLimNodeParents(NodeId limId, std::set& parents); + + /** + * \internal + * \brief This method gives back the parent of the given lim node. + */ + NodeId getLimNodeParent(NodeId limId) const; + + /** + * \internal + * \brief Sorts the nodes into declarations and statements. + * \param idMaps [in] The maps which contain the mapping between the ids and the nodes + * \param nodes [in] A vector which contains the sortable node ids + * \param declarations [out] A vector which will contain clang::Decl* nodes + * \param statements [out] A vector which will contain clang::Stmt* nodes + */ + void sortNodesByType(const NodeIDMaps &idMaps + , std::vector &nodes + , std::vector &declarations + , std::vector &statements + ); + + + + void computeSimilarityAttributes(columbus::genealogy::CloneInstance& ci); + + enum F_attributes { F1 = 1, F2, F3, F4, F5, F6 }; + const std::string* getFString(F_attributes F, const columbus::genealogy::CloneInstance& ci) { + switch (F) { + case F1: return &ci.getPath(); + case F2: return nullptr; + case F3: return &ci.getF3_HeadNodeUniqueName(); + case F4: return &ci.getF4_AncestorUniqueName(); + case F5: return &ci.getF4_AncestorUniqueName(); + case F6: return &ci.getF6_LexicalStructure(); + default: return nullptr; + } + } + double getStringSimilarity(std::string& s1, std::string& s2, double& dist, double* alpha, unsigned int limit); + double distanceF(F_attributes F, const columbus::genealogy::CloneInstance& from, const columbus::genealogy::CloneInstance& to, double& dist, const double& bound, double* alpha); + + + /** + * \internal + * \brief compute F3 distance between clone intances + */ + double distanceF3(const columbus::genealogy::CloneInstance& from, const columbus::genealogy::CloneInstance& to, double& dist, double& bound, double* alpha); + + double distanceF1(const columbus::genealogy::CloneInstance& from, const columbus::genealogy::CloneInstance& to, double& dist, double& bound, double* alpha); + + double distanceF4(const columbus::genealogy::CloneInstance& from, const columbus::genealogy::CloneInstance& to, double& dist, double& bound, double* alpha); + + double distanceF2(const columbus::genealogy::CloneInstance& from, const columbus::genealogy::CloneInstance& to, double& dist, double& bound, double* alpha); + + double distanceF5(const columbus::genealogy::CloneInstance& from, const columbus::genealogy::CloneInstance& to, double& dist, double& bound, double* alpha); + + double distanceF6(const columbus::genealogy::CloneInstance& from, const columbus::genealogy::CloneInstance& to, double& dist, double& bound, double* alpha); + /** + * \internal + * \brief compute similarity between clone instances + */ + double similarity(const columbus::genealogy::CloneInstance& from, const columbus::genealogy::CloneInstance& to); + + /** + * \internal + * \return the id of the component or 0 + */ + NodeId getLimComponenetIdByName(const std::string& name, const columbus::lim::asg::Factory& factory); + + const std::string& getComponentName(columbus::NodeId limId, const columbus::lim::asg::Factory& factory) const; + + /** + * \internal + * \brief get clone instances of 'system' + * \return vector of clone instances + */ + std::vector getInstancesOfaSystem(const genealogy::System& system) const; + + +public: + /** + * \brief start duplicate code mining + */ + int dcminer(); + + /** + * \internal + * \brief set dump genealogy to graphml + */ + void setDumpgraphml(bool dump); + + /** + * \brief gives back node kind at 'position' from serialized asg + * \param position [in] node position + * \return node kind + */ + int getNodeKindAt(unsigned int position) const; + + /** + * \brief get node at 'position' from serialized asg + * \param position [in] node position + * \return node + */ + const ASTNodeInfo* getNode(unsigned int sequencePosition) const; + + /** + * \brief return true, if parameter is separator + * \param value [in] value parameter + * \return true, if value is separator, otherwise is false + */ + bool isSeparator(int value) const; + + /** + * \brief return true, if parameter is depth sign + * \param value [in] value parameter + * \return true, if value is depth sign, otherwise is false + */ + bool isDecDepthSign(int value) const; + + /** + * \brief return true, if the id at 'sequencePosition' is an asg node (Not a special node kind ex: the end of node sign) + * \param value [in] value parameter + * \return true, if id at sequencePosition is node, otherwise is false + */ + bool isASGNode(unsigned int sequencePosition) const; + + /** + * \brief dump last system to output stream + * \param o [in] output stream + */ + void dumpLastSystem(std::ostream& o); + + /** + * \brief export binary graph + * \param filename [in] file name + */ + void exportGraph(const std::string& filename); + + /** + * \brief get clone instance start position in serialized asg + * \param id [in] node id + * \return ci position + */ + unsigned int getPosition(NodeId id) const; + + /** + * \brief get clone class length in serialized asg + * \param id [in] node id + * \return ci length + */ + unsigned int getLength(NodeId id) const; + + static columbus::Key getUniformPathKey(columbus::Key key, StrTable& strtable); + + + /** + * \brief calculate clone class length + * \param cc [in] clone class + * \return the clone class length + */ + static unsigned int getLength(const genealogy::CloneClass& cc); + + /** + * \brief get the number of the clone instances of 'cc' i.e. the parameter clone class + * \param cc [in] clone class + * \return the number of instances of 'cc' + */ + static unsigned int getRealNumberCi(const genealogy::CloneClass& cc); + + /** + * \brief get the calculate number of the clone classes of 'sys' i.e. the parameter system + * \param sys [in] system + * \return the number of clone classes of 'sys' + */ + static unsigned int getRealNumberCC(const genealogy::System& sys); + + /** + * \brief set filterout + * \param out [in] the filterout to be set + */ + void setFilterOut(std::ostream& out); + + /** + * \brief compute covered lines of clones + */ + void computeCoveredLines(); + + /** + * \brief calculate CCO metric + */ + // TODO rename + void calculateCOOForLangASG(columbus::NodeId componenetId, const std::string&); + + friend class ProcessCC; + friend class ProcessPatternFilter; + +}; + + +} + +#endif + diff --git a/cl/DCF-CPP/inc/messages.h b/cl/DCF-CPP/inc/messages.h new file mode 100644 index 0000000..19a1418 --- /dev/null +++ b/cl/DCF-CPP/inc/messages.h @@ -0,0 +1,154 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _DCF_M_H_ +#define _DCF_M_H_ + +// error +#define CMSG_SIMPLE_STRING_TRANSMIT_ERR common::WriteMsg::mlError, "%s\n" +#define CMSG_NO_INPUT_FILES common::WriteMsg::mlError, "Error: No input file\n" +#define CMSG_NO_INPUT_LIM_FILE common::WriteMsg::mlError, "Error: No input lim file\n" +#define CMSG_FAILED_OPEN_FILE common::WriteMsg::mlError, "Error: Cannot open file: \"%s\"" +#define CMSG_NO_INFO_FOR_FILE common::WriteMsg::mlError, "The information for the %s component is missing in the %s file.\n" +#define CMSG_NO_COMPONET_FILE common::WriteMsg::mlError, "The the file of %s component is missing \n" +#define CMSG_DIFFERENT_NODEKINDS common::WriteMsg::mlError, "Error: Clone position object is a method, but LIM node is not. [%s:%d]\n" +#define CMSG_NO_FILE_FOR_THE_CLONE common::WriteMsg::mlError, "Error: No file is found for a clone instance (%u)\n" +#define CMSG_TOO_MANY_FILES_FOR_THE_CLONE common::WriteMsg::mlError, "Error: Too many files are found for a clone instance (%u)\n" + +// warning +#define CMSG_GENALOGY_WILL_NOT_BE_SAVED common::WriteMsg::mlWarning, "%s\n Warning: Genalogy will not be saved!\n" +#define CMSG_ERROR_IN_SERIALIZED_ASG_SEQUENCE common::WriteMsg::mlWarning, "Warning: Missing end sequence of the node %d\n" +#define CMSG_FILTER_FILE_CANNOT_BE_LOADED common::WriteMsg::mlWarning, "Warning: Filter file cannot be loaded: \"%s\"\n" +#define CMSG_FILTER_FILE_OLD common::WriteMsg::mlWarning, "Warning: Filter file (%s) is older than the input file. Filter file is not used.\n" +#define CMSG_NOT_ENOUGH_MEMORY_TO_EVOLUTE common::WriteMsg::mlWarning, "Warning: Not enough memory to find all previous version of clone instances.\n" +#define CMSG_FILENAME_COMPONENT_MATCH common::WriteMsg::mlWarning, "Warning: Component has found with filename only! (%s)\n" +#define CMSG_ADDING_PATH_TO_FILTER common::WriteMsg::mlWarning, "Warning: Clone detection in file (%s) need to be skiped due to it seems to contain too much clones. (Probably a generated file.)\n" +#define CMSG_NO_COMPILATION_UNIT_FOUND common::WriteMsg::mlWarning, "Warning: Can't find compilation unit file: %s\n" + +// normal +#define CMSG_GENERATING_CLONE_INSTANCES common::WriteMsg::mlNormal, "Generating clone instances...\n" +#define CMSG_FREE_VERSION_MESSAGE common::WriteMsg::mlNormal, "There is no valid license!\n" + +#define CMSG_FAILED common::WriteMsg::mlNormal, "Failed\n" +#define CMSG_DONE_N common::WriteMsg::mlNormal, "Done\n" +#define CMSG_USE_PATTERNFILTER common::WriteMsg::mlNormal, "Using patternFilter...\n" +#define CMSG_DETECTING_CLONES common::WriteMsg::mlNormal, "Detecting clones...\n" +#define CMSG_APPLYING_FILTERS common::WriteMsg::mlNormal, "Applying filters...\n" +#define CMSG_BUILD_CLONE_TREE common::WriteMsg::mlNormal, "Building clone tree...\n" +#define CMSG_LOADING common::WriteMsg::mlNormal, "Loading: %s\n" +#define CMSG_LOADING_AND_PERCENTAGE common::WriteMsg::mlNormal, "Loading (%.2f): %s\n" +#define CMSG_LOADING_CPP_COMPONENT common::WriteMsg::mlNormal, "Loading (%.2f) (#AST %d): %s\n" +#define CMSG_INITIALIZING_LIM common::WriteMsg::mlNormal, "Initializing lim...\n" +#define CMSG_STATISTICS common::WriteMsg::mlNormal, "Statistics:\n" +#define CMSG_DETECTING_TIME common::WriteMsg::mlNormal, "\tDetection time :%lu 1/100sec\n" +#define CMSG_PEAK_MEMORY_USAGE common::WriteMsg::mlNormal, "\tPeak memory usage :%lu MByte\n" +#define CMSG_COMPUTING_METRICS common::WriteMsg::mlNormal, "Computing metrics...\n" +#define CMSG_COMPUTING_EVOLUTION_METRICS common::WriteMsg::mlNormal, "Computing evolution metrics...\n" +#define CMSG_COMPUTING_COVERED_NODES common::WriteMsg::mlNormal, "Computing clone coverage...\n" +#define CMSG_START_FINALIZING common::WriteMsg::mlNormal, "Finalizing...\n" +#define CMSG_START_EVOLUTION_MAPPING common::WriteMsg::mlNormal, "Evolution mapping...\n" + +// debug +#define CMSG_SERIALIZED_AST_SIZE common::WriteMsg::mlDebug, "Debug: Size of the serialized AST:%lu\n" +#define CMSG_RUL_FILE_NOT_SET common::WriteMsg::mlDebug, "Debug: .rul file not specified. \"%s\" is used.\n" +#define CMSG_RUL_FILE_FOUND common::WriteMsg::mlDebug, "Debug: .rul file found: \"%s\"\n" +#define CMSG_FILTERED_OUT common::WriteMsg::mlDebug, "Debug: File filtered out: %s\n" +#define CMSG_THE_LIM_INPUT_FILE common::WriteMsg::mlDebug, "Debug: The LIM input file: \"%s\"\n" +#define CMSG_LINE_INFO_CASE common::WriteMsg::mlDebug, "Debug: Line info capitalization: %s\n" + +#define CMSG_PROBALBLY_CLONES_FOUND common::WriteMsg::mlDebug,"Debug: Searching for clone candidates is done. Building instances\n" +#define CMSG_LOAD_ASG_DONE common::WriteMsg::mlDebug,"Debug: Loading of the ASG is done" +#define CMSG_CONVERTING_TO_GRAPH common::WriteMsg::mlDebug,"Debug: Converting to graph\n" +#define CMSG_BUILD_CE common::WriteMsg::mlDebug, "Debug: The CE cache" +#define CMSG_CLONE_INSTANCE common::WriteMsg::mlDDDDebug,"Debug: CloneInstance%d:\n" +#define CMSG_SD_ON common::WriteMsg::mlDDDDebug,"%s(%d) on %d %d %s ,%d\n" +#define CMSG_CURRENT_COMPONENT_ID common::WriteMsg::mlDebug, "Debug: The ID of the current component node in LIM:%d\n" + +#define CMSG_LINE_INFO_CASE_LOWERED "lower case" +#define CMSG_LINE_INFO_CASE_DEFAULT "default case" +#define CMSG_MINIMUM_NUMBER_OF_LINES common::WriteMsg::mlDebug, "Debug: The minimum lines of clones: %d\n" +#define CMSG_MINIMUM_NUMBER_OF_ASG_NODES common::WriteMsg::mlDebug, "Debug: The minimum ASG nodes of clones: %d\n" +#define CMSG_MAXIMUM_PATTERN_SIZE common::WriteMsg::mlDebug, "Debug: Maximum of the single pattern size: %d\n" +#define CMSG_MINIMUM_PATTERN_FULL_LENGTH common::WriteMsg::mlDebug, "Debug: Minimum of the full length of the repeating pattern: %d\n" +#define CMSG_DETECTING_CODE_DUPLICATIONS common::WriteMsg::mlDebug, "Debug: Detecting code duplications\n" +#define CMSG_FILTER_RESULT_REDIRECTED_TO_STANDARD_OUT common::WriteMsg::mlDebug, "Debug: Filter result redirected to standard out\n" +#define CMSG_FILTER_RESULT_REDIRECTED_INTO_FILE common::WriteMsg::mlDebug, "Debug: Filter result redirected into file: \"%s\" \n" +#define CMSG_DUMPING_OUTPUT_TO_FILE common::WriteMsg::mlDebug, "Debug: Dumping output to file: \"%s\"\n" +#define CMSG_DUMPING_OUTPUT_TO_STANDARD_OUTPUT common::WriteMsg::mlDebug, "Debug: Dumping output to standard out\n" +#define CMSG_DONE_D common::WriteMsg::mlDebug, "Debug: Done\n" +#define CMSG_DONE_IN common::WriteMsg::mlDebug, "Debug: Done in %lu (1/100sec)\n" +#define CMSG_NEED_TO_SKIP common::WriteMsg::mlDebug, "Debug: Need to skip:%s\n" +#define CMSG_NODE_FILTERED_OUT common::WriteMsg::mlDebug, "Debug: %lu node(s) were filtered out\n" +#define CMSG_CLONE_DETECTION_DONE_IN common::WriteMsg::mlDebug, "Debug: Clone detection done in %lu (1/100sec)\n" +#define CMSG_MEM_USED common::WriteMsg::mlDebug, "Debug: Mem used:%lu (MByte) \n" +#define CMSG_FINALIZE_DONE_IN common::WriteMsg::mlDebug, "Debug: Finalization is done in %lu (1/100sec)\n" +#define CMSG_CLONE_VISITOR_RUNNING common::WriteMsg::mlDebug, "Debug: Clone visitor running...\n" +#define CMSG_INITIALIZING_GENEALOGY common::WriteMsg::mlDebug, "Debug: Initializing Genealogy...\n" +#define CMSG_START_CLONE_NAMING common::WriteMsg::mlDebug, "Debug: Start clone naming...\n" +#define CMSG_COMPUTING_COVERAGE_AND_GENERATE_GRAPH_FORM_LIM common::WriteMsg::mlDebug,"Debug: Computing coverage and generate graph from lim...\n" +#define CMSG_COMPUTING_COVERAGE_DONE common::WriteMsg::mlDebug, "Debug: Coverage calculation is done\n" +#define CMSG_CREATE_BACKUP common::WriteMsg::mlDebug, "Debug: Creating backup...\n" +#define CMSG_SAVE_GENEALOGY common::WriteMsg::mlDebug, "Debug: Saving genealogy...\n" +#define CMSG_EXPORT_METRICS common::WriteMsg::mlDebug, "Debug: Exporting metrics...\n" +#define CMSG_CAUSE common::WriteMsg::mlDebug, "Debug: Cause: %s\n" +#define CMSG_INC_CE common::WriteMsg::mlDDebug, "Debug: Increasing CE on %d because it is connected to the %d:%d which distance is %d. %s\n" +#define CMSG_INC_CE_ALWAYS "It has to be counted always." +#define CMSG_INC_CE_ONCE "It has to be counted only once." + +#define CMSG_DIFFERENT_NUMBER_OF_VISITED_NODES common::WriteMsg::mlDebug, "Debug: Different number of nodes were visited during the preorder and postorder visit! (Pre:%lu Post:%lu)\n" +#define CMSG_MISSING_NODE_FORM_POSTORDER common::WriteMsg::mlDebug, "Debug: Missing node from postorder list: %p (0x%08X) " + +// TODO ez alatt 4-5 sorral van meg string konstans !!! +#define CMSG_MORE_END_THEN_BEGIN common::WriteMsg::mlDebug, "Debug: There is a problem with the lim node traversal (more lim node end exist than begin)." +#define CMSG_NODE_NO_POS_CACHE common::WriteMsg::mlDebug, "Debug: The %d NodeId is not found in the position cache\n" + +// ddd debug +#define CMSG_START_VISIST common::WriteMsg::mlDDDDebug, "DDDDebug: START:[%s|%s|%d L:%d] CD:%d AD:%d\n" +#define CMSG_START_EVOLUTION_MAPPING_SYSTEM_SET(PHASE) common::WriteMsg::mlDDDDebug, "DDDDebug: Start evolution mapping ["#PHASE"]...\n" +#define CMSG_ADD_NODE_TO_SEQ common::WriteMsg::mlDDDDebug, "DDDDebug: %d node %s [%s:%d ]\n" +#define CMSG_ADD_NODE_TO_SEQ_END common::WriteMsg::mlDDDDebug, "DDDDebug: %d node end \n" +#define CMSG_FUND_REPEATING_SEQ common::WriteMsg::mlDDDDebug, "Found cl on %d to %d :%d\n" +#define CMSG_FUND_REPEATING_SEQ_2 common::WriteMsg::mlDDDDebug, " on %d to %d\n" +#define CMSG_FUND_REPEATING_SEQ_3 common::WriteMsg::mlDDDDebug, " create with %d id\n" +#define CMSG_FUND_REPEATING_SEQ_4 common::WriteMsg::mlDDDDebug, " the instance start %d found align to %d - %d id\n" +#define CMSG_FUND_REPEATING_SEQ_5 common::WriteMsg::mlDDDDebug, " the interval is to short %d \n" +#define CMSG_FUND_REPEATING_SEQ_6 common::WriteMsg::mlDDDDebug, " on %d space does not matter.\n" + +#define CMSG_SETTING_METRICS_FOR common::WriteMsg::mlDDDDebug, "Setting metric for: %s(%d):%s\n" +#define CMSG_M_CLONECOVERAGE common::WriteMsg::mlDDDDebug, "\tClone coverage (CC): %f\n" +#define CMSG_M_CLONEEMBEDDEDNESS common::WriteMsg::mlDDDDebug, "\tClone embeddedness (CE): %d\n" + + +// exception +#define CMSG_EX_UNABLE_TO_DETERMINE_THE_LINE_INFO "Unable to determine the line info!" +#define CMSG_EX_HASH_CODE_MISMATCH(FNAME) "Hash code mismatch!(" + FNAME + ")" +#define CMSG_EX_MISSING_COMPONENT_FOR_CI "Component node is missing for the clone instance!" +#define CMSG_EX_THIS_METHOD_SHOULD_NOT_BE_CALLED "This method should not be called!" +#define CMSG_EX_MERGE_FAILED "Failed to merge the preorder and postorder list!" +#define CMSG_EX_NO_COMPILATION_UNIT_FOUND(COMPUNIT) "Can't find compilation unit (" + COMPUNIT + ") in the LIM!" + + +// other +#define CMSG_OS_RUNNING_CLONE_LENGTH_FILTER "Running \"Clone length filter\"" +#define CMSG_OS_RUNNING_OCCURANCE_FILTER "Running \"Occurance filter\"" +#define CMSG_OS_RUNNING_CROSSING_FILTER "Running \"Crossing filter\"" +#define CMSG_OS_FILTERING_CLONES_WITH_REPEATING_LINES "Filtering clones with repeating lines" + +#endif diff --git a/cl/DCF-CPP/src/AbstractFilter.cpp b/cl/DCF-CPP/src/AbstractFilter.cpp new file mode 100644 index 0000000..a1547b9 --- /dev/null +++ b/cl/DCF-CPP/src/AbstractFilter.cpp @@ -0,0 +1,28 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "../inc/AbstractFilter.h" + +AbstractFilter::AbstractFilter() : currentValue(0){ +} + +int AbstractFilter::getMaxValue() { + return 0; +} diff --git a/cl/DCF-CPP/src/CloneLengthFilter.cpp b/cl/DCF-CPP/src/CloneLengthFilter.cpp new file mode 100644 index 0000000..0602451 --- /dev/null +++ b/cl/DCF-CPP/src/CloneLengthFilter.cpp @@ -0,0 +1,30 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "../inc/CloneLengthFilter.h" +#include "../inc/dcm.h" + +bool CloneLengthFilter::isFiltered(const columbus::genealogy::CloneClass& cc) { + unsigned int l = 0; + l = columbus::DuplicatedCodeMiner::getLength(cc); + + if(l < length) return true; + return false; +} diff --git a/cl/DCF-CPP/src/ClonePositioned.cpp b/cl/DCF-CPP/src/ClonePositioned.cpp new file mode 100644 index 0000000..486dd15 --- /dev/null +++ b/cl/DCF-CPP/src/ClonePositioned.cpp @@ -0,0 +1,30 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "../inc/ClonePositioned.h" + +columbus::StrTable ASTNodeInfo::paths; + + +void ASTNodeInfo::dump() +{ + printf("Key:%u, Line: (%u %u %u %u), NodeId: %u, LIM NodeId: %u, TUid: %u, ComponentId: %u, TUPathKey: %u\n", + path, line, col, endLine, endCol, nodeId, limNodeId, translationUnitId, limComponentId, TUPathKey); +} diff --git a/cl/DCF-CPP/src/CppSerializeAST.cpp b/cl/DCF-CPP/src/CppSerializeAST.cpp new file mode 100644 index 0000000..b649103 --- /dev/null +++ b/cl/DCF-CPP/src/CppSerializeAST.cpp @@ -0,0 +1,892 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "../inc/CppSerializeAST.h" +#include "../inc/messages.h" +#include "../inc/Config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +using namespace std; +using namespace llvm; +using namespace clang; +using namespace common; +using namespace tooling; + + +using columbus::FilterState; + +extern Config config; + +namespace columbus +{ + void updateMemoryStat(Config &config, const char* msg = nullptr); +} + +ASTSerializerConsumer::ASTSerializerConsumer(columbus::SerializationData& serializationData, CppCloneVisitor* ccVitor) + : serializationData(serializationData) + , ccVitor(ccVitor) + , prevPath() + , prevLine (0) + , filter(ccVitor->getFilter()) + , filterLogStream(ccVitor->getFilterLogStream()) +{ +} + +string getCannocializedPath(ASTContext &context, common::Cache& cannonicalizedPathCache, clang::FileID fileID) +{ + string path; + const auto cacheSearchResult = cannonicalizedPathCache.getValue(fileID); + + if(cacheSearchResult.found) + path = cacheSearchResult.value; + else + { + if (fileID.isValid()) + { + const auto fileEntry = context.getSourceManager().getFileEntryForID(fileID); + if (fileEntry != nullptr) + { + path = pathCanonicalize(fileEntry->getName().str()); + path = path.c_str(); + } + } + + cannonicalizedPathCache.setValue(fileID, path); + } + + return path; +} + +void ASTSerializerConsumer::addSeparator() +{ + serializationData.nodeKindSequence.push_back(ccVitor->getSeparator()); + serializationData.nodeInfoSequence.push_back(NULL); +} + + +void ASTSerializerConsumer::HandleTranslationUnit(ASTContext &context) +{ + auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("HandleTranslationUnit()"); + + ASTSerializerVisitor::NodeList pre, post; + shared_ptr nodeIds; + if (context.getTranslationUnitDecl() != nullptr) + { + nodeIds = columbus::generateNodeIDMaps(context); + pre.reserve(nodeIds->id2node.size()); + post.reserve(nodeIds->id2node.size()); + perfSectionHandler.addTimeStamp("generateNodeIDMaps"); + ASTSerializerVisitor(context, false, pre, ccVitor, localSerializationData).TraverseDecl(context.getTranslationUnitDecl()); + perfSectionHandler.addTimeStamp("ASTSerializerVisitor-pre"); + ASTSerializerVisitor(context, true, post, ccVitor, localSerializationData).TraverseDecl(context.getTranslationUnitDecl()); + perfSectionHandler.addTimeStamp("ASTSerializerVisitor-post"); + } + + ASTSerializerVisitor::NodeList merged; + merged = ASTSerializerVisitor::merge(pre, post); + columbus::updateMemoryStat(config); + + perfSectionHandler.addTimeStamp("ASTSerializerVisitor-merge"); + + common::Cache cannonicalizedPathCache; + columbus::ASTFilter myFilter(config.filterfile, context, &cannonicalizedPathCache, true, true); // softfilter + perfSectionHandler.addTimeStamp("ASTSerializerVisitor-filter"); + + //Needed for the line filter. If the given line already had visited then we skip that subtree. + bool isSerializationTurnedOn = true; + void* turnOnAt; + + columbus::NodeId prevLimNode = 0; + set serializedNodes; + + for(auto& nodeInfo : merged) + { + nodeInfo.nodeId = nodeIds->node2id[nodeInfo.nodePtr]; + unsigned line = nodeInfo.line_start; + +/* + // DEBUG + if (nodeInfo.nodeId == 0) + { + printf("."); + fflush(stdout); + } +*/ + /////////////////////// create cp objects /////////////////////// + if (!((nodeInfo.nodeKind & NodeMask::NodeEndMask) == NodeEndType::NodeEnd)) + { + ccVitor->updateLimNodeStack(nodeInfo.nodeId, false); + + + if(isSerializationTurnedOn) + { + std::string lPath = getCannocializedPath(context, cannonicalizedPathCache, nodeInfo.pathID); + + if (lPath.empty()) + continue; + + if (serializationData.visitedLines.count(columbus::LineIdentifier(ccVitor->getLimFactory().getStringTable().get(lPath),line)) != 0) + { + common::WriteMsg::write(common::WriteMsg::mlDDebug,"\nThe %s %d has already been visited.\n", lPath.c_str(),line); + + //insert the last visited line + serializationData.visitedLines.insert(columbus::LineIdentifier(ccVitor->getLimFactory().getStringTable().set(prevPath.c_str()),prevLine)); + prevPath = lPath; + prevLine = line; + + //turn off the serialization and save the pointer when we have to turn on again + isSerializationTurnedOn = false; + turnOnAt = nodeInfo.nodePtr; + continue; + } + + if((ccVitor->getPrevPath() != lPath) && ccVitor->getFileNamesByComponent()) + { + ccVitor->assignSrcFileToComponenet(lPath, ccVitor->getCurrentLimComponent()); + ccVitor->setPrevPath(lPath); + addSeparator(); // File separator +/* + // Debug + printf("LineChange: %s\n", lPath.c_str()); +*/ + } + + //softfilter && limfilter + if ((myFilter.getFilterState(nodeInfo.nodePtr) == FilterState::NotFiltered) && + (!ccVitor->isFilteredInLim(ccVitor->getCurrentLimNode()))) + { + + //line filter + if ((prevPath!=lPath || line!=prevLine) && lPath != "") + { + serializationData.visitedLines.insert(columbus::LineIdentifier(ccVitor->getLimFactory().getStringTable().set(prevPath.c_str()),prevLine)); + prevPath = lPath; + prevLine = line; + } + + //check in pattern filter + if(filter != NULL && filter->find(nodeInfo.nodeId) != filter->end()) + { + if (filterLogStream) + *filterLogStream << "Pattern filter remove: " << lPath << " [" << nodeInfo.line_start << ":" << nodeInfo.column_start << " | " << nodeInfo.line_end << ":" << nodeInfo.column_end << "] (" << nodeInfo.nodeKind << ")\n"; + } + else + { + ASTNodeInfo *astNodeInfo = new ASTNodeInfo(lPath, + nodeInfo.line_start, + nodeInfo.column_start, + nodeInfo.line_end, + nodeInfo.column_end, + nodeInfo.nodeId, + ccVitor->getCurrentLimNode(), + ccVitor->getCurrentTranslationUnitId(), + ccVitor->getCurrentTranslationUnitPath(), + ccVitor->getCurrentLimComponent()); + + auto extraLineInfoIt = localSerializationData.ASTNodeExtraLineMap.find(nodeInfo.nodePtr); + + if (extraLineInfoIt != localSerializationData.ASTNodeExtraLineMap.end()) + { + for (auto line : extraLineInfoIt->second) + { +/* + // Debug + printf("Extra Sor: %d\n", line); +*/ + astNodeInfo->addLine(line); + } + } + + //cp->dump(); + auto nodeKind = nodeInfo.nodeKind; + if (config.ofc && + ((nodeKind & NodeMask::NodeTypeMask) == NodeType::Declaration) && + (((nodeKind & NodeMask::NodeKindMask) == clang::Decl::Kind::Function) || ((nodeKind & NodeMask::NodeKindMask) == clang::Decl::Kind::CXXMethod))) + { + addSeparator(); + } + + serializationData.nodeKindSequence.push_back(nodeKind); + serializationData.nodeInfoSequence.push_back(astNodeInfo); + serializedNodes.insert(nodeInfo.nodePtr); + + if(prevLimNode != ccVitor->getCurrentLimNode()) + prevLimNode = ccVitor->getCurrentLimNode(); + } + } + else + { + //filtered in ast or in LIM + } + + } + else + { + //serialization turned off + } + + } + else // end node + { + ccVitor->updateLimNodeStack(0, true); + if(isSerializationTurnedOn) + { + //softfilter + if (myFilter.getFilterState(nodeInfo.nodePtr) == FilterState::NotFiltered) + { + const auto cacheSearchResult = cannonicalizedPathCache.getValue(nodeInfo.pathID); + + if (cacheSearchResult.found && cacheSearchResult.value.empty()) + continue; + + //lim filter + if( !ccVitor->isFilteredInLim(ccVitor->getCurrentLimNode())) + { + // pattern filter + if(filter == NULL || filter->find(nodeInfo.nodeId) == filter->end()) + { + serializationData.nodeKindSequence.push_back(-2); + serializationData.nodeInfoSequence.push_back(NULL); + } + } + } + } + else + { + if(nodeInfo.nodePtr == turnOnAt) + { + isSerializationTurnedOn = true; + turnOnAt = nullptr; + } + } + } + + } // end for + + columbus::updateMemoryStat(config); + + //insert into the last visited line + serializationData.visitedLines.insert(columbus::LineIdentifier(ccVitor->getLimFactory().getStringTable().set(prevPath.c_str()),prevLine)); + + /////////////////////// END cp objects /////////////////////// + perfSectionHandler.addTimeStamp("for"); + + //convert local references map's pointers to ASTNodeInfo references + columbus::Key currentASTPathKey = ASTNodeInfo::getPathKey(ccVitor->getCurrentTranslationUnitPath()); + for(auto reference : localSerializationData.ASTNodeReferenceMap) + { + const auto fromNode = nodeIds->node2id[reference.first]; + const auto toNode = nodeIds->node2id[reference.second]; + if ((toNode == 0) || (fromNode == 0)) + continue; + + bool serializedEndNode = false; + if (serializedNodes.find(reference.first) != serializedNodes.end()) + serializedEndNode = true; + else if (serializedNodes.find(reference.second) != serializedNodes.end()) + serializedEndNode = true; + + // At least one end of the reference edge is serialized so we store the reference + if (serializedEndNode) + { + serializationData.referencesMap[currentASTPathKey][fromNode] = toNode; + serializationData.nodeReferencePathMap[currentASTPathKey][fromNode] = ASTNodeInfo::getPathKey(getCannocializedPath(context, cannonicalizedPathCache, localSerializationData.ASTNodeFileIDMap[reference.first])); + serializationData.nodeReferencePathMap[currentASTPathKey][toNode] = ASTNodeInfo::getPathKey(getCannocializedPath(context, cannonicalizedPathCache, localSerializationData.ASTNodeFileIDMap[reference.second])); + } + } + + columbus::updateMemoryStat(config); + + addSeparator(); // Translation unit separator +// Debug +// ASTSerializerVisitor::dumpNodeList(merged, &context); +// for (size_t i = 0; i < serializationData.nodeKindSequence.size(); ++i) +// { +// auto nodeKind = serializationData.nodeKindSequence[i]; +// auto nodeInfo = serializationData.nodeInfoSequence[i]; +// if (nodeInfo) +// WriteMsg::write(WriteMsg::mlDebug, "0x%08X File:%s Line:%d Col:%d\n", nodeKind, nodeInfo->getStringPath().c_str(), nodeInfo->getLine(), nodeInfo->getCol()); +// else +// WriteMsg::write(WriteMsg::mlDebug, "0x%08X\n", nodeKind); +// +// } +// perfSectionHandler.addTimeStamp("ref map conversion"); +} + + +ASTSerializerVisitor::ASTSerializerVisitor(ASTContext &context, bool post, NodeList& nodes, CppCloneVisitor* ccVitor, LocalSerializationData &localSerializationData) + : context(context) + , post (post) + , nodes (nodes) + , ccVitor(ccVitor) + , localSerializationData(localSerializationData) +{} + +bool ASTSerializerVisitor::VisitStmt(Stmt *s) +{ + if (post) + nodes.push_back({s, clang::FileID(), ((std::uint32_t)s->getStmtClass() & NodeMask::NodeKindMask) | NodeType::Statement | NodeEndType::NodeEnd, 0, 0, 0, 0, 0 }); + else + { + nodes.push_back({s, clang::FileID(), ((std::uint32_t)s->getStmtClass() & NodeMask::NodeKindMask) | NodeType::Statement, 0, 0, 0, 0, 0 }); + ccVitor->incVisitedNodes(); + } + fillLocationInfo(s, nodes.back()); + + // collect references for CE metirc + if (!post) + { + if(clang::DeclRefExpr::classof(s)) + { + clang::DeclRefExpr* ref = llvm::dyn_cast(s); + addToRefernceMaps(ref->getDecl(), s); + } + else if (clang::MemberExpr::classof(s)) + { + clang::MemberExpr* memberRef = llvm::dyn_cast(s); + clang::ValueDecl *memberDecl = nullptr; + if ((memberRef != nullptr) && ((memberDecl = memberRef->getMemberDecl()) != nullptr)) + addToRefernceMaps(memberDecl, s); + } + else if (clang::ExplicitCastExpr::classof(s)) + { + const clang::ExplicitCastExpr* explicitCast = llvm::dyn_cast(s); + if (explicitCast != nullptr) + { + addToRefernceMaps(getReferencedRecordDecl(explicitCast->getTypeAsWritten().getTypePtr()), s); + } + } + else if (clang::BinaryOperator::classof(s)) + { + const clang::BinaryOperator* binaryOperator = llvm::dyn_cast(s); + if (binaryOperator->isLogicalOp()) + nodes.back().nodeKind |= NodeBOType::LogicalBinaryOperator; + } + else if (clang::IfStmt::classof(s)) + { + const clang::IfStmt* ifStmt = llvm::dyn_cast(s); + + addExtraLineInfo(s, ifStmt->getIfLoc()); + if (ifStmt->getElse() != nullptr) + addExtraLineInfo(s, ifStmt->getElseLoc()); + } + + } + return true; +} + + +void ASTSerializerVisitor::addToRefernceMaps(clang::Decl* decl, void *node) +{ + if (decl == nullptr) + return; + + NodeInfo referencedPositionInfo; + fillLocationInfo(decl, referencedPositionInfo); + + localSerializationData.ASTNodeReferenceMap[node] = decl; + localSerializationData.ASTNodeFileIDMap[node] = nodes.back().pathID; + localSerializationData.ASTNodeFileIDMap[decl] = referencedPositionInfo.pathID; +} + +void ASTSerializerVisitor::addExtraLineInfo(void* node, const SourceLocation& sourceLocation) +{ + localSerializationData.ASTNodeExtraLineMap[node].insert(context.getSourceManager().getPresumedLineNumber(sourceLocation)); +} + + + +bool ASTSerializerVisitor::VisitDecl(Decl *d) +{ + if (post) + nodes.push_back({d, clang::FileID(), ((std::uint32_t)d->getKind() & NodeMask::NodeKindMask) | NodeType::Declaration | NodeEndType::NodeEnd, 0, 0, 0, 0, 0 }); + else + { + nodes.push_back({d, clang::FileID(), ((std::uint32_t)d->getKind() & NodeMask::NodeKindMask) | NodeType::Declaration, 0, 0, 0, 0, 0 }); + ccVitor->incVisitedNodes(); + + + // collect extra line info for CLLC and LLDC + if (clang::TagDecl::classof(d)) + { + clang::TagDecl* tagDecl = llvm::dyn_cast(d); + if (tagDecl->getBraceRange().isValid()) + { + auto braceRange = tagDecl->getBraceRange(); + + // Since the end of the braceRange is probably the same as the end + // position of the node we dont have to add it + addExtraLineInfo(d, braceRange.getBegin()); + } + } + + // collect references for CE metirc + if (clang::VarDecl::classof(d)) + { + clang::VarDecl* varDecl = llvm::dyn_cast(d); + addToRefernceMaps(getReferencedRecordDecl(varDecl->getType().getTypePtr()), d); + } + } + + fillLocationInfo(d, nodes.back()); // TODO: Calculate it only in preorder mode and reuse it in the postorder visit + return true; +} + + +clang::RecordDecl* ASTSerializerVisitor::getReferencedRecordDecl(const clang::Type* typePtr) const +{ + if (clang::RecordType::classof(typePtr)) + { + const clang::RecordType* recordType = llvm::dyn_cast(typePtr); +// recordType->getDecl()->dump(); + return recordType->getDecl(); + } + else if (clang::PointerType::classof(typePtr)) + { + const clang::PointerType* pointerType = llvm::dyn_cast(typePtr); + return getReferencedRecordDecl(pointerType->getPointeeType().getDesugaredType(context).getTypePtr()); + } + else if (clang::ReferenceType::classof(typePtr)) + { + const clang::ReferenceType* referenceType = llvm::dyn_cast(typePtr); + return getReferencedRecordDecl(referenceType->getPointeeType().getDesugaredType(context).getTypePtr()); + } + else if (clang::MemberPointerType::classof(typePtr)) + { + const clang::MemberPointerType* memberPointerType = llvm::dyn_cast(typePtr); + return getReferencedRecordDecl(memberPointerType->getClass()); + } + else if (clang::ArrayType::classof(typePtr)) + { + const clang::ArrayType* arrayType = llvm::dyn_cast(typePtr); + return getReferencedRecordDecl(arrayType->getElementType().getDesugaredType(context).getTypePtr()); + } + + return nullptr; +} + +template +void ASTSerializerVisitor::fillLocationInfo(T* node, NodeInfo& nodeInfo) +{ + PresumedLoc PLoc_start, PLoc_end; + const SourceManager& sm = context.getSourceManager(); + + PLoc_start = sm.getPresumedLoc(node->getBeginLoc()); + PLoc_end = sm.getPresumedLoc(node->getEndLoc()); + + if (PLoc_start.isValid() && PLoc_end.isValid()) + { + nodeInfo.pathID = PLoc_start.getFileID(); + nodeInfo.line_start = PLoc_start.getLine(); + nodeInfo.column_start = PLoc_start.getColumn(); + nodeInfo.line_end = PLoc_end.getLine(); + nodeInfo.column_end = PLoc_end.getColumn(); + } +} + +bool ASTSerializerVisitor::shouldTraversePostOrder() const +{ + return post; +} + +ASTSerializerVisitor::NodeList ASTSerializerVisitor::merge(const NodeList& pre, const NodeList& post) +{ + NodeList result; + stack nodeStack; + auto preItemIterator = pre.begin(); + auto postItemIterator = post.begin(); + + if (pre.size() != post.size()) + { + WriteMsg::write(CMSG_DIFFERENT_NUMBER_OF_VISITED_NODES, pre.size(), post.size()); + for (auto& preNode : pre) + { + auto found = find_if(post, [&preNode](auto& postNode){return preNode.nodePtr == postNode.nodePtr; }); + if (found == post.end()) + { + WriteMsg::write(CMSG_MISSING_NODE_FORM_POSTORDER, preNode.nodePtr, preNode.nodeKind); + dumpNodeInfo(preNode, nullptr); + } + } + throw columbus::Exception(COLUMBUS_LOCATION, CMSG_EX_MERGE_FAILED); + } + + result.reserve(pre.size() * 2); + // Insert the first element into the stack + nodeStack.push(preItemIterator->nodePtr); + result.push_back(*preItemIterator); + ++preItemIterator; + + while (postItemIterator != post.end()) + { + if (!nodeStack.empty() && (nodeStack.top() == postItemIterator->nodePtr)) + { + result.push_back(*postItemIterator); + ++postItemIterator; + nodeStack.pop(); + } + else + { + if(preItemIterator == pre.end()){ + throw columbus::Exception(COLUMBUS_LOCATION, CMSG_EX_MERGE_FAILED); + } + result.push_back(*preItemIterator); + nodeStack.push(preItemIterator->nodePtr); + ++preItemIterator; + } + } + + return result; +} + +void ASTSerializerVisitor::dumpNodeInfo(const NodeInfo& nodeInfo, ASTContext *context) +{ + WriteMsg::write(WriteMsg::mlDebug, "%p (0x%08X):", nodeInfo.nodePtr, nodeInfo.nodeKind); + switch (nodeInfo.nodeKind & NodeMask::NodeTypeMask) + { + case NodeType::Statement: + { + Stmt* stmt = static_cast(nodeInfo.nodePtr); + WriteMsg::write(WriteMsg::mlDebug, "%s", stmt->getStmtClassName()); + dumpLineInfo(context, stmt, nodeInfo.nodeKind); + break; + + } + case NodeType::Declaration: + { + Decl* decl = static_cast(nodeInfo.nodePtr); + WriteMsg::write(WriteMsg::mlDebug, "%s", decl->getDeclKindName()); + dumpLineInfo(context, decl, nodeInfo.nodeKind); + break; + } + } + WriteMsg::write(WriteMsg::mlDebug, "\n"); +} + +void ASTSerializerVisitor::dumpNodeList(const ASTSerializerVisitor::NodeList& nodes, ASTContext *context) +{ + for (auto& nodeInfo : nodes) + { + dumpNodeInfo(nodeInfo, context); + } +} + +template +void ASTSerializerVisitor::dumpLineInfo(ASTContext *context, T* node, int nodeKind) +{ + if (context == nullptr) + return; + + FullSourceLoc fullLocation; + if ((nodeKind & NodeMask::NodeEndMask) == NodeEndType::NodeEnd) + fullLocation = context->getFullLoc(node->getEndLoc()); + else + fullLocation = context->getFullLoc(node->getBeginLoc()); + + if (fullLocation.isValid()) + WriteMsg::write(WriteMsg::mlDebug, " %s", fullLocation.printToString(context->getSourceManager()).c_str()); +} + +SerializeAction::SerializeAction(columbus::SerializationData& serializationData, CppCloneVisitor* ccVitor) + : serializationData(serializationData) + , ccVitor(ccVitor) + {} + +unique_ptr SerializeAction::CreateASTConsumer(CompilerInstance &Compiler, StringRef InFile) +{ + return unique_ptr(new ASTSerializerConsumer(serializationData, ccVitor)); +} + + +///////////////////////////////// +// +// CppCloneVisitor definitions +// +///////////////////////////////// + + +CppCloneVisitor::CppCloneVisitor(columbus::LimOrigin& limOrigin, columbus::lim::asg::Factory* limFactory) + : limOrigin(limOrigin) + , limFactory(limFactory) + , filter(NULL) + , visitedNodes(0) + , uniqueValue(-1) + , decDepthSign(-2) + , separatorCounter(-3) + , prevPath("") + , fileNamesByComponent(nullptr) + , tuPathToCompAndTuId(nullptr) + , filterLogStream(nullptr) + {} + + +void CppCloneVisitor::serializeComponent(const list& compilationUnits, columbus::SerializationData& serializationData) +{ + auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("serializeComponent()"); + + tooling::FixedCompilationDatabase compilationDatabase(".", { "-fno-delayed-template-parsing" }); + + for (auto& compilationUnit : compilationUnits) + { + if (common::pathFindExtension(compilationUnit) != "ast") + continue; + + if (!common::pathFileExists(compilationUnit)) + { + common::WriteMsg::write(CMSG_NO_COMPILATION_UNIT_FOUND, compilationUnit.c_str()); + continue; + } + + columbus::NodeId compilationUnitId = getLimCompilationIdByName(compilationUnit); + if (compilationUnitId != 0) + { + setCurrentTranslationUnitId(compilationUnitId); + currentTUPath = compilationUnit; + if(tuPathToCompAndTuId){ + auto it = (*tuPathToCompAndTuId).find(currentTUPath); + if(it == tuPathToCompAndTuId->end() ){ + (*tuPathToCompAndTuId)[currentTUPath] = make_pair(getCurrentLimComponent(), getCurrentTranslationUnitId()); + } + } + + tooling::ClangTool Tool(compilationDatabase, {compilationUnit}); + Tool.clearArgumentsAdjusters(); + Tool.appendArgumentsAdjuster(tooling::getClangStripOutputAdjuster()); + Tool.appendArgumentsAdjuster(tooling::getInsertArgumentAdjuster("-fsyntax-only", tooling::ArgumentInsertPosition::BEGIN)); + + Tool.run(newSerializeActionFactory(serializationData).get()); + } + else + throw columbus::Exception(COLUMBUS_LOCATION, CMSG_EX_NO_COMPILATION_UNIT_FOUND(compilationUnit)); + } +} + +unique_ptr CppCloneVisitor::newSerializeActionFactory(columbus::SerializationData& serializationData) +{ + class SimpleFrontendActionFactory : public FrontendActionFactory + { + public: + SimpleFrontendActionFactory(columbus::SerializationData& serializationData, CppCloneVisitor* ccVitor) + : serializationData(serializationData) + , ccVitor(ccVitor) + { + } + + unique_ptr create() override { return unique_ptr(new SerializeAction(serializationData, ccVitor)); } + private: + columbus::SerializationData& serializationData; + CppCloneVisitor* ccVitor; + }; + + return unique_ptr(new SimpleFrontendActionFactory(serializationData, this)); +} + + +void CppCloneVisitor::setFilter(std::set& filter) { + this->filter = &filter; +} + +void CppCloneVisitor::clearFilter() { + this->filter = NULL; +} + +bool CppCloneVisitor::evoluteLimNode( const ASTNodeInfo* n, bool end ){ + columbus::NodeId parsedLimNodeID = 0; + + if (end) { + if (currentLimNode.size()) { + currentLimNode.pop(); + return true; + } else { + common::WriteMsg::write(CMSG_MORE_END_THEN_BEGIN ); + } + } else { + if (parseLimNodeId(n, parsedLimNodeID)) { + currentLimNode.push(parsedLimNodeID) ; + return true; + } else if (currentLimNode.empty()) { + currentLimNode.push(limFactory->getRoot()->getId()); + return true; + }else{ + currentLimNode.push(currentLimNode.top()); + } + } + return false; +} + +void CppCloneVisitor::updateLimNodeStack(const columbus::NodeId astNodeId, const bool end) +{ + if (end) + { + if (currentLimNode.size()) + currentLimNode.pop(); + else + common::WriteMsg::write(CMSG_MORE_END_THEN_BEGIN); + } + else + { + columbus::NodeId correspondingLimNodeId = limOrigin.getLimIdToCompIdAndCppId(currentTUId, astNodeId); + if (correspondingLimNodeId != 0) + currentLimNode.push(correspondingLimNodeId); + else if (currentLimNode.empty()) + currentLimNode.push(limFactory->getRoot()->getId()); + else + currentLimNode.push(currentLimNode.top()); + } +} + +bool CppCloneVisitor::parseLimNodeId( const ASTNodeInfo* n, columbus::NodeId& limNodeID ){ + columbus::NodeId tmpNode = limOrigin.getLimIdToCompIdAndCppId( currentTUId, n->getId() ); + if (tmpNode != 0) { + limNodeID = tmpNode; + return true; + } + return false; +} + + + +columbus::NodeId CppCloneVisitor::getCurrentLimNode(){ + return currentLimNode.empty() ? currentLimComponent : currentLimNode.top(); + //return currentLimNode.empty() ? 0 : currentLimNode.top(); +} +void CppCloneVisitor::setCurrentLimComponent(columbus::NodeId id){ + currentLimComponent = id; +} + +void CppCloneVisitor::setCurrentTranslationUnitId(columbus::NodeId id){ + currentTUId = id; +} + +columbus::NodeId CppCloneVisitor::getCurrentLimComponent(){ + return currentLimComponent; +} + +columbus::NodeId CppCloneVisitor::getCurrentTranslationUnitId(){ + return currentTUId; +} + +int CppCloneVisitor::getVisitedNodesNumber(){ + return visitedNodes; +} + +void CppCloneVisitor::incVisitedNodes(){ + visitedNodes++; +} + +void CppCloneVisitor::decVisitedNodes(){ + visitedNodes--; +} + +void CppCloneVisitor::resetVisitedNodesNumber(){ + visitedNodes = 0; +} + +bool CppCloneVisitor::isSepDecDepthSign(int s) { + return (s==decDepthSign); +} + +int CppCloneVisitor::getUniqueValue() { + return uniqueValue; +} + +int CppCloneVisitor::getDecDepthSign() { + return decDepthSign; +} + +int CppCloneVisitor::getSeparator() +{ + --separatorCounter; +#ifndef NDEBUG + if(separatorCounter == INT_MIN) + throw columbus::Exception(COLUMBUS_LOCATION,"Too many separator character created!"); +#endif + return separatorCounter; +} + +columbus::NodeId CppCloneVisitor::getLimCompilationIdByName( const std::string& name) +{ + columbus::lim::asg::Factory::TurnFilterOffSafely filterOff(*limFactory); + + const auto* componentNode = static_cast< const columbus::lim::asg::base::Component*>(limFactory->getPointer(currentLimComponent)); + if (componentNode != nullptr) + { + for(auto it = componentNode->getCompilationUnitListIteratorBegin(); it != componentNode->getCompilationUnitListIteratorEnd(); ++it) + { + if (columbus::lim::asg::Common::getFullPath((*it)) == name) + return it->getId(); + } + } + + return 0; +} + +const std::string& CppCloneVisitor::getCurrentTranslationUnitPath() const { + return currentTUPath; +} + +const columbus::lim::asg::Factory& CppCloneVisitor::getLimFactory(){ + return *limFactory; +} + +//Ez lehet hogy nem is kell +void CppCloneVisitor::assignSrcFileToComponenet( const std::string &lPath ,columbus::NodeId currentLimComponent) +{ + (*fileNamesByComponent)[currentLimComponent].insert(limFactory->getStringTable().set(lPath.c_str())); + for ( columbus::lim::asg::ListIterator + it = limFactory->getReverseEdges().constIteratorBegin(currentLimComponent,columbus::lim::asg::edkComponent_Contains); + it != limFactory->getReverseEdges().constIteratorEnd(currentLimComponent,columbus::lim::asg::edkComponent_Contains); + ++it) { + assignSrcFileToComponenet(lPath,it->getId()); + } +} + +bool CppCloneVisitor::isFilteredInLim(columbus::NodeId limId){ + return limFactory->getIsFiltered(limId); +} + +std::set* CppCloneVisitor::getFilter(){ + return filter; +} + +void CppCloneVisitor::setFilterLogStream(std::ostream *out) +{ + filterLogStream = out; +} + +std::ostream *CppCloneVisitor::getFilterLogStream() const +{ + return filterLogStream; +} diff --git a/cl/DCF-CPP/src/LanguageFactory.cpp b/cl/DCF-CPP/src/LanguageFactory.cpp new file mode 100644 index 0000000..5df65da --- /dev/null +++ b/cl/DCF-CPP/src/LanguageFactory.cpp @@ -0,0 +1,64 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "../inc/LanguageFactory.h" + +#include +#include + +using namespace std; + +namespace columbus { + + LanguageFactory::LanguageFactory() + : loaded(false) + , limComponentNameFileNameMap() + , hashCodes() + {} + + LanguageFactory::~LanguageFactory() { + } + + std::string LanguageFactory::getFileNameByComponentId( const std::string& id ) + { + std::map::iterator it = limComponentNameFileNameMap.find(id); + if (it != limComponentNameFileNameMap.end()) { + return it->second; + } + return std::string(); + } + + const std::map& LanguageFactory::getLimComponentNameFileNameMap() const + { + return limComponentNameFileNameMap; + } + + void LanguageFactory::fillComponentList( std::list listOfInputFile ) + { + for (std::list::iterator it = listOfInputFile.begin();it != listOfInputFile.end();++it) { + } + } + + + + + +} + diff --git a/cl/DCF-CPP/src/RepeatingLinesFilter.cpp b/cl/DCF-CPP/src/RepeatingLinesFilter.cpp new file mode 100644 index 0000000..e8bc520 --- /dev/null +++ b/cl/DCF-CPP/src/RepeatingLinesFilter.cpp @@ -0,0 +1,67 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include + +#include "../inc/RepeatingLinesFilter.h" +#include "../inc/dcm.h" +#include "../inc/messages.h" + + +bool RepeatingLinesFilter::isFiltered(const columbus::genealogy::CloneClass& cc) { + for(columbus::genealogy::ListIterator cloneInstanceIt = cc.getItemsListIteratorBegin();cloneInstanceIt != cc.getItemsListIteratorEnd();++cloneInstanceIt) { + const columbus::genealogy::CloneInstance& ci = *cloneInstanceIt; + std::vector cppNodes; + unsigned int counter = 0; + bool firstLine = true; + bool firstNode = true; + long currentLine = 0; + unsigned ci_position = dcm.getPosition(ci.getId()); + unsigned length = dcm.getLength(cc.getId()); + for(unsigned int positionIndex = ci_position; positionIndex < ci_position + length; ++positionIndex) + { + const ASTNodeInfo* position = dcm.getNode(positionIndex); + if(!position) continue; + if(firstNode) + currentLine = position->getLine(); + else if(currentLine != position->getLine()) { + // we are in a new line + counter = 0; + currentLine = position->getLine(); + firstLine = false; + } + if(firstLine) { + cppNodes.push_back(dcm.getNodeKindAt(positionIndex)); + } else { + //we are just comparing + //:HACK + if(cppNodes.size() <= counter) + return false; + if (cppNodes[counter++] != dcm.getNodeKindAt(positionIndex)) { + //the clone class does not consist of same lines only + return false; + } + } + firstNode=false; + } + } // iterating over all the clone instances in this class + return true; +} + diff --git a/cl/DCF-CPP/src/StatementFilter.cpp b/cl/DCF-CPP/src/StatementFilter.cpp new file mode 100644 index 0000000..7a06dd3 --- /dev/null +++ b/cl/DCF-CPP/src/StatementFilter.cpp @@ -0,0 +1,47 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + + +#include "../inc/messages.h" +#include "../inc/dcm.h" +#include "../inc/StatementFilter.h" +#include "../inc/CppSerializeAST.h" + + + +bool StatementFilter::isFiltered( const columbus::genealogy::CloneClass& cc ) +{ + for(columbus::genealogy::ListIterator cloneInstanceIt = cc.getItemsListIteratorBegin();cloneInstanceIt != cc.getItemsListIteratorEnd();++cloneInstanceIt) { + const columbus::genealogy::CloneInstance& ci = *cloneInstanceIt; + unsigned ci_position = dcm.getPosition(ci.getId()); + unsigned length = dcm.getLength(cc.getId()); + for(unsigned int positionIndex = ci_position; positionIndex < ci_position + length; ++positionIndex) + { + int nodeKind = dcm.getNodeKindAt(positionIndex); + + if((nodeKind & NodeMask::NodeTypeMask) == NodeType::Statement) + { + return false; + } + } + } // iterating over all the clone instances in this class + return true; +} + diff --git a/cl/DCF-CPP/src/dcm.cpp b/cl/DCF-CPP/src/dcm.cpp new file mode 100644 index 0000000..4a0b36f --- /dev/null +++ b/cl/DCF-CPP/src/dcm.cpp @@ -0,0 +1,4491 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include //sajat + +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "../inc/dcm.h" +#include "../inc/StatementFilter.h" +#include "../inc/CloneOccuranceFilter.h" +#include "../inc/CloneLengthFilter.h" +#include "../inc/RepeatingLinesFilter.h" +#include "../inc/messages.h" +#include "../inc/DistanceVisitor.h" +#include "../inc/CPPNamedVisitor.h" + + +using namespace common; + +#define ROOT_COMPONENT_NAME "" + +namespace columbus { + + + void updateMemoryStat(Config &config, const char* msg) + { + static long long last = 0; + using namespace common; + memstat ms = getProcessUsedMemSize(); + if (config.stat.memory_peak < ms.size) + config.stat.memory_peak = ms.size; + if ((msg != nullptr ) || ((ms.size - last) != 0)) { + if (msg != nullptr) + WriteMsg::write(WriteMsg::mlDebug,"[%s] Mem ussage %d MByte diff %I64d (peak:%lu MByte)\n", msg, ms.size / 1024 / 1024, (ms.size - last) / 1024 / 1024, config.stat.memory_peak / 1024 / 1024); + else + WriteMsg::write(WriteMsg::mlDDebug,"Mem ussage %d MByte diff %I64d (peak:%lu MByte)\n", ms.size/1024/1024, (ms.size - last) / 1024 / 1024, config.stat.memory_peak / 1024 / 1024); + + } + last = ms.size; + } + + + using namespace suffix_array; + + + std::map ciIdToAST; + + + //when genealogy is maintained the previous factory is also needed + + void DuplicatedCodeMiner::setDumpgraphml( bool dump ) + { + dumpGraphml = dump; + } + +#define DEBUGPRINTF(x) +#define DEBUGPRINTF2(x) +#define DEBUGPRINTF3(x) + + int DuplicatedCodeMiner::getNodeKindSequenceSize(){ + return serializationData.nodeKindSequence.size(); + } + + void DuplicatedCodeMiner::computeSimilarityAttributes(columbus::genealogy::CloneInstance& ci) + { + columbus::genealogy::CloneClass* cc = ci.getCloneClass(); + vector ciRootsList = getInstanceIds(ci); + + columbus::genealogy::Component* component = ci.getComponent(); + if (component == NULL) + throw Exception(COLUMBUS_LOCATION, CMSG_EX_MISSING_COMPONENT_FOR_CI); + + const ASTNodeInfo* cp; + + //load ast + ASTWithNodeIDMaps astWithNodeIdMaps = loadAST(ciIdToAST[ci.getId()], /*cacheLast=*/true); + unsigned int pos = positions[ci.getId()]; + cp = getNode(pos); + + const int nodeKind = getNodeKindAt(pos); + + // For computing F1, F2, F3, F4, F5 only the first subtree is used! + + /* + F1: Name of the file containing the clone instance. + F2: Position of the clone instance inside the clone class. + F3: The unique name of the head node - if the unique name exists (just for named entities). + F4: Otherwise, the unique name of the first named ancestor in the AST. + F5: The relative position of the code segment inside its first named ancestor. + F6: Lexical structure of the clone instance. + */ + + // ============================ Computing F1 Attribute ========================================= + // The path (F1) is always stored + // ============================ Computing F2 Attribute ========================================= + + if (ci.getF2_OrdinalNumber() == 0) { + int order = 1; + for (columbus::genealogy::ListIterator lIter1=cc->getItemsListIteratorBegin();lIter1!=cc->getItemsListIteratorEnd();++lIter1) { + if (lIter1->getId()==ci.getId()) + break; + order++; + } + common::WriteMsg::write(WriteMsg::mlDDDDebug,"the F2 is %d for %d\n",order,ci.getId()); + ci.setF2_OrdinalNumber(order); + } + + // ========================= Computing F3 Attribute ========================================== + + + if((nodeKind & NodeMask::NodeTypeMask) == NodeType::Declaration){ + clang::Decl* d = static_cast(astWithNodeIdMaps.nodeIdMaps->id2node[cp->getId()].first); + if(auto* namedNode = clang::dyn_cast(d)){ + if (ci.getF3_HeadNodeUniqueName().empty()) { + ci.setF3_HeadNodeUniqueName(namedNode->getQualifiedNameAsString()); + common::WriteMsg::write(WriteMsg::mlDDDDebug,"the F3 is %s for %d\n",ci.getF3_HeadNodeUniqueName().c_str(),ci.getId()); + } + } + } + + + // ============================ Computing F4 Attribute ======================================= + const clang::NamedDecl* ptrNamedAncestor = nullptr; + std::string namedAncestor = ""; + + if((nodeKind & NodeMask::NodeTypeMask) == NodeType::Declaration) + { + clang::Decl* d = static_cast(astWithNodeIdMaps.nodeIdMaps->id2node[cp->getId()].first); + //Need to find the first declaration, because a definition also a declaration and it's first named ancestor can be the clang::TranslationUnitDecl. + while(!d->isFirstDecl()){ + d = d->getPreviousDecl(); + } + + clang::DynTypedNodeList parents = getParents(&astWithNodeIdMaps.astUnit->getASTContext(), clang::DynTypedNode::create(*d)); + while((parents.size() > 0) && (parents[0].get() == NULL)) + { + if (auto namedDecl = parents[0].get()) + { + namedAncestor = namedDecl->getQualifiedNameAsString(); + ptrNamedAncestor = namedDecl; + break; + } + else + parents = getParents(&astWithNodeIdMaps.astUnit->getASTContext(), parents[0]); + } + } + else if((nodeKind & NodeMask::NodeTypeMask) == NodeType::Statement) + { + clang::DynTypedNodeList parents = astWithNodeIdMaps.astUnit->getASTContext().getParents( *(static_cast(astWithNodeIdMaps.nodeIdMaps->id2node[cp->getId()].first)) ); + + while((parents.size() > 0) && (parents[0].get() == NULL)) + { + if (auto namedDecl = parents[0].get()) + { + namedAncestor = namedDecl->getQualifiedNameAsString(); + ptrNamedAncestor = namedDecl; + break; + } + else + parents = getParents(&astWithNodeIdMaps.astUnit->getASTContext(), parents[0]); + } + } + + if (ci.getF4_AncestorUniqueName().empty()) { + if (namedAncestor != "") { + ci.setF4_AncestorUniqueName(namedAncestor); + common::WriteMsg::write(WriteMsg::mlDDDDebug,"the F4 is %s for %d\n",ci.getF4_AncestorUniqueName().c_str(),ci.getId()); + } + } + + + // ================================= Computing F5 Attribute ================================== + // The L2 is the node count of the instanse so normally it can not be 0. If it is zero then it means that it is not calculated yet. + if (ci.getF5_L2() == 0 && ptrNamedAncestor != nullptr) { + + if ((nodeKind & NodeMask::NodeKindMask) != clang::Decl::Kind::Namespace) { +not_namespace: + DistanceVisitor dv(astWithNodeIdMaps.nodeIdMaps->id2node[cp->getId()].first); + clang::NamedDecl* parent = const_cast(ptrNamedAncestor); + clang::ASTPrePostTraverser astTraverser(astWithNodeIdMaps.astUnit->getASTContext(), parent, dv); + astTraverser.run(); + + ci.setF5_L1(dv.getL1()); + ci.setF5_L2(dv.getL2()); + ci.setF5_L3(dv.getL3()); + common::WriteMsg::write(WriteMsg::mlDDDDebug,"the F5 is L1 %d L2 %d L3 %d for %d\n",dv.getL1(),dv.getL2(),dv.getL3(),ci.getId()); + } + else + { + if((nodeKind & NodeMask::NodeTypeMask) != NodeType::Declaration){ + //if the nodeKind is clang::Decl::Kind::Namespace but the node type not a declaration but a statement then that is not a namespace + goto not_namespace; + } + } + } + + + // ================================ Computing F6 Attribute =================================== + if (ci.getF6_LexicalStructure().empty()) { + std::string source; + clang::PrintingPolicy pp = astWithNodeIdMaps.astUnit->getASTContext().getPrintingPolicy(); + pp.Indentation = 0; + pp.IncludeNewlines = false; + for(vector::const_iterator ciRootsListIt = ciRootsList.begin(); ciRootsListIt != ciRootsList.end(); ++ciRootsListIt) + { + + const auto &nodeInfo = astWithNodeIdMaps.nodeIdMaps->id2node[*ciRootsListIt]; + if(nodeInfo.second == AstNodeType::DECL) + { + clang::Decl* decl = (clang::Decl*)nodeInfo.first; + llvm::raw_string_ostream s(source); + decl->print(s, pp, 0); + } + else if(nodeInfo.second == AstNodeType::STMT) + { + clang::Stmt* stmt = (clang::Stmt*)nodeInfo.first; + llvm::raw_string_ostream s(source); + stmt->printPretty(s, nullptr, pp, 0, ""); + } + } + // Since the Decl printer does not use the IncludeNewlines policy we have to remove the newlines + replace(source.begin(), source.end(), '\n', ' '); + ci.setF6_LexicalStructure(source); + common::WriteMsg::write(WriteMsg::mlDDDDebug,"the F6 is %s for %d\n",ci.getF6_LexicalStructure().c_str(),ci.getId()); + + } + + } + + double DuplicatedCodeMiner::similarity(const columbus::genealogy::CloneInstance& from, const columbus::genealogy::CloneInstance& to) { + static unsigned long counter = 0; + double inf=std::numeric_limits::infinity(); + ++counter; + DEBUGPRINTF(printf("[%lu]Similarity:%d -> %d:", counter, from.getId(), to.getId());) + + double dist = 0.0; + double bound = 0.1; + + double alpha[7]={ 0.0, 0.3122, 0.6365, 0.2066, 0.4293, 0.1101, 0.5080}; + + columbus::genealogy::CloneClass& fromClass=*(from.getCloneClass()); + columbus::genealogy::CloneClass& toClass=*(to.getCloneClass()); + + if (fromClass.getHeadNodeKind() != toClass.getHeadNodeKind()) { + DEBUGPRINTF(printf("head mismatch (inf)\n");) + dist = inf; + } + // when the instances don't share the same number of root nodes + if(from.getRootLength() != to.getRootLength()) { + common::WriteMsg::write(WriteMsg::mlDDDDebug,"root length mismatch (inf) [%d][%d]\n", from.getRootLength(), to.getRootLength()); + dist = inf; + } + + double partial[7] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + + // ========================= Computing F3 ========================================== + if (dist < bound) { + if (!from.getF3_HeadNodeUniqueName().empty()) { + if (!to.getF3_HeadNodeUniqueName().empty()) { + + std::string uniqueNameFrom = from.getF3_HeadNodeUniqueName(); + std::string uniqueNameTo = to.getF3_HeadNodeUniqueName(); + + if (uniqueNameFrom != uniqueNameTo) { + + unsigned int n_max=max(uniqueNameFrom.size(),uniqueNameTo.size()); + + double similarity = ((double)common::math::editDistance(uniqueNameFrom, uniqueNameTo)) / n_max; + dist+=alpha[3]*similarity; + partial[3] = alpha[3]*similarity; + } + + } else { // to is not named + dist += alpha[3]; + partial[3] = alpha[3]; + } + } else if (!to.getF3_HeadNodeUniqueName().empty()) { // from is not named but to is named + dist += alpha[3]; + partial[3] = alpha[3]; + } + } + // ======================== Computing F1============================================= + if (dist < bound) { + string fromPath = from.getPath(); + string toPath = to.getPath(); + + if (!fromPath.empty()) { + if (!toPath.empty()) { + boost::filesystem::path p1(fromPath); + fromPath = (*--p1.end()).string(); + boost::filesystem::path p2(toPath); + toPath = (*--p2.end()).string(); + if (fromPath != toPath) { + unsigned int n_max=max(fromPath.size(),toPath.size()); + double pathDistance=((double)common::math::editDistance(fromPath, toPath)) / n_max; + dist += alpha[1] * pathDistance; + partial[1] = alpha[1] * pathDistance; + } + } else { + dist += alpha[1]; + partial[1] = alpha[1]; + } + } else if (!toPath.empty()) { + dist += alpha[1]; + partial[1] = alpha[1]; + } + } + // ============================ Computing F2 ========================================= + // Currently if order1 != order2, then the overall distance is set to inf later on. + // Solution / TODO: modify weight of F2 in alpha array + // Temporary solution: don't use F2 distance at all + /*if (dist < bound) { + int order1 = from.getF2_OrdinalNumber(); + int order2 = to.getF2_OrdinalNumber(); + + if (order1 != order2) { + double lineDistance=fabs((double)order1-order2); + dist += alpha[2] * lineDistance; + partial[2] = alpha[2] * lineDistance; + } + }*/ + // ============================ Computing F4 ========================================== + if (dist < bound) { + if (!from.getF4_AncestorUniqueName().empty()) { + if (!to.getF4_AncestorUniqueName().empty()) { + std::string uniqueNameFrom = from.getF4_AncestorUniqueName(); + std::string uniqueNameTo = to.getF4_AncestorUniqueName(); + if (uniqueNameFrom != uniqueNameTo) { + unsigned int n_max=max(uniqueNameFrom.size(),uniqueNameTo.size()); + double similarity = ((double)common::math::editDistance(uniqueNameTo,uniqueNameFrom)) / n_max; + dist += alpha[4] * similarity; + partial[4] = alpha[4] * similarity; + } + } else { + dist += alpha[4]; + partial[4] = alpha[4]; + } + } else if (!to.getF4_AncestorUniqueName().empty()) { + dist += alpha[4]; + partial[4] = alpha[4]; + } + } + // ================================= Computing F5 ================================================ + if (dist < bound) { + if (!from.getF4_AncestorUniqueName().empty()) { + if (!to.getF4_AncestorUniqueName().empty()) { + + unsigned int L = from.getF5_L1() + from.getF5_L2() + from.getF5_L3(); + unsigned int Lv= to.getF5_L1() + to.getF5_L2() + to.getF5_L3(); + double LvpL=(double)Lv/((double)L); + double similarity=pow(((double)(to.getF5_L1() +1 ) / (from.getF5_L1() +1 ))-LvpL, 2)+ + pow(((double)(to.getF5_L3()+1)/(from.getF5_L3() + 1))-LvpL,2); + + dist += alpha[5]*similarity; + partial[5] = alpha[5] * similarity; + } else { + common::WriteMsg::write(WriteMsg::mlDDDDebug,"F5 FAIL (inf): %lf\n", dist); + dist = inf; + } + } else if (!to.getF4_AncestorUniqueName().empty()) { + common::WriteMsg::write(WriteMsg::mlDDDDebug,"F5 FAIL (inf): %lf\n", dist); + dist = inf; + } + } + + // ================================ Computing F6 ========================================== + if (dist < bound) { + string fromSource = from.getF6_LexicalStructure(); + string toSource = to.getF6_LexicalStructure(); + + if (!fromSource.empty()) { + if (!toSource.empty()) { + if (fromSource != toSource) { + unsigned int n_max=max(fromSource.size(),toSource.size()); + unsigned int limit = (unsigned int)(((bound-dist)/alpha[6])*n_max)+1; + unsigned int edit=common::math::editDistance(fromSource, toSource, limit); + common::WriteMsg::write(WriteMsg::mlDDDDebug,"F6:[%s][%s][%d]:%d\n",fromSource.c_str(), toSource.c_str(), limit, edit); + + double similarity=((double)edit)/n_max; + dist += alpha[6] * similarity; + partial[6] = alpha[6] * similarity; + } + common::WriteMsg::write(WriteMsg::mlDDDDebug,"F6:[%s]\n",fromSource.c_str()); + } else { + dist += alpha[6]; + partial[6] = alpha[6]; + } + } else if (!toSource.empty()) { + dist += alpha[6]; + partial[6] = alpha[6]; + } + } + + common::WriteMsg::write(WriteMsg::mlDDDDebug,"SIMILARITY(%lu): %lf (1:%lf, 2:%f, 3:%f, 4:%f, 5:%f, 6:%f)\n", counter, dist, partial[1], partial[2], partial[3], partial[4], partial[5], partial[6]); + DEBUGPRINTF2(fflush(stdout);) + + if (dist > bound) + { + return inf; + } + return dist; + } + + vector DuplicatedCodeMiner::getInstancesOfaSystem(const genealogy::System& system) const + { + vector instances; + for (genealogy::ListIterator classItemsIter = system.getCloneClassesListIteratorBegin(); classItemsIter != system.getCloneClassesListIteratorEnd(); ++classItemsIter) + for (genealogy::ListIterator instanceItemsIter = classItemsIter->getItemsListIteratorBegin(); instanceItemsIter != classItemsIter->getItemsListIteratorEnd(); ++instanceItemsIter) + instances.push_back(const_cast(&(*instanceItemsIter))); + return instances; + } + + + inline static void clearNodeIdSequence(std::vector& nodeInfoSequence); + + class ProcessCC : public SuffixArray::CloneVisitor + { + public: + ProcessCC(const ProcessCC&); + ProcessCC operator=(const ProcessCC&); + ProcessCC() + : needToSkip(NULL) + , clone_counter(NULL) + , dcm(NULL) + , maxCCSize(0) + {} + virtual ~ProcessCC(){} + std::set* needToSkip; + std::map* clone_counter; + DuplicatedCodeMiner *dcm; + unsigned int maxCCSize; + DuplicatedCodeMiner::CloneClassPotentialCloneInstanceMap potentialCloneInstances; + std::list> filters; + + public: + virtual void visit(SuffixArray::CloneClass& suffixCl) { + if(!dcm) + return; + unsigned int position = suffixCl.position[0]; + unsigned int length = suffixCl.length; + unsigned int ctl=0; + bool foundl=false; + while (ctlisASGNode(position+ctl)) { + foundl=true; + break; + } else + ctl++; + } + if (!foundl) { + //the pattern does not contain any CPP nodes + return; + } + if (maxCCSize) { + const ASTNodeInfo* cp = dcm->getNode(position+ctl); + std::string path = cp->getStringPath(); + std::map::iterator iter=clone_counter->find(path); + if (needToSkip->find(boost::to_lower_copy(path))==needToSkip->end()) { + if (iter==clone_counter->end()) { + clone_counter->insert(std::map::value_type(path,1)); + } else { + if (++(*iter).second == maxCCSize) { + needToSkip->insert(boost::to_lower_copy(path)); + common::WriteMsg::write(CMSG_NEED_TO_SKIP, path.c_str()); + return; + } + } + } else + return; + } + +/* + printf("SuffixCC length:%u\n", suffixCl.length); + for (unsigned i = 0; i < suffixCl.num; ++i) + { + printf("%u, ", suffixCl.position[i]); + } + printf("\n"); + */ + dcm->alignCloneClass(Aligner::SyntaxBoundary, suffixCl, potentialCloneInstances); + } + + void buildCloneInstances() + { + for (DuplicatedCodeMiner::CloneClassPotentialCloneInstanceMap::const_iterator ccIt = potentialCloneInstances.begin(); ccIt != potentialCloneInstances.end(); ++ccIt) { + unsigned lastend = 0; + genealogy::CloneClass& cc = (genealogy::CloneClass&)dcm->genealogyFact->getRef(ccIt->first); + for (set::const_iterator ciIt = ccIt->second.begin(); ciIt != ccIt->second.end(); ++ciIt) { + if (lastend > 0 && ciIt->startPosition + ciIt->I->a <= lastend){ + continue; + } + if (!dcm->containsInstanceAtPositon(ciIt->startPosition + ciIt->I->a, cc)) { + lastend = ciIt->startPosition + ciIt->I->b; + dcm->createCloneInstance(ciIt->startPosition + ciIt->I->a, ciIt->I->b - ciIt->I->a + 1, ciIt->startPosition, ciIt->I->intervals, cc); + } + } + + for (auto filter : filters) + { + if(filter->checkCloneClass(cc)) + { + for(genealogy::ListIterator cloneInstanceIt = cc.getItemsListIteratorBegin(); cloneInstanceIt != cc.getItemsListIteratorEnd(); ++cloneInstanceIt) + { //clone instance + const auto ciId = cloneInstanceIt->getId(); + dcm->limNodeCloneInstanceMap.erase(ciId); + dcm->limComponentCloneInstanceMap.erase(ciId); + dcm->cloneInstanceRootNodesMap.erase(ciId); + ciIdToAST.erase(ciId); + } + + const auto ccId = cc.getId(); + dcm->cloneClassMap.erase(dcm->cloneClassFingerprintMap[ccId]); + dcm->genealogyFact->destroyNode(ccId); + dcm->cloneClassFingerprintMap.erase(ccId); + break; + } + } + + // If the cc is not filtered then we set the fingerprint and rootnodes attributes of the clone classes and instances + if (dcm->genealogyFact->getExist(ccIt->first)) + { + cc.setFingerprint(dcm->cloneClassFingerprintMap[cc.getId()]); + for(genealogy::ListIterator cloneInstanceIt = cc.getItemsListIteratorBegin(); cloneInstanceIt != cc.getItemsListIteratorEnd(); ++cloneInstanceIt) + { + const_cast(*cloneInstanceIt).setRootNodes(dcm->cloneInstanceRootNodesMap[cloneInstanceIt->getId()]); + } + } + + } + } + + void addFilter(shared_ptr filter) + { + filters.push_back(filter); + } + + }; + + class ProcessPatternFilter : public SuffixArray::CloneVisitor { + public: + ProcessPatternFilter() + : sequence(NULL) + , min_inst_length(0) + , dcm(NULL) + { + + } + virtual ~ProcessPatternFilter(){} + ProcessPatternFilter(const ProcessPatternFilter&); + ProcessPatternFilter operator= (const ProcessPatternFilter&); + Sequence* sequence; + unsigned min_inst_length; + + std::set filteredNodeIndexes; + DuplicatedCodeMiner *dcm; + + public: + virtual void visit(SuffixArray::CloneClass& suffixCl) { + unsigned int drop_begin = 0; + unsigned int drop_end = 0; + + unsigned length = suffixCl.length; + + + //for(set::iterator it = suffixCl.position.begin(), prevPos = suffixCl.position.begin(); it != suffixCl.position.end(); ++it) { + sort(suffixCl.position, suffixCl.position+suffixCl.num); + for(unsigned it = 0, prevPos = 0; it < suffixCl.num; ++it) { + + if((suffixCl.position[it] - suffixCl.position[prevPos]) == length ) { + + if(drop_begin == 0) + drop_begin = suffixCl.position[prevPos]; + else + drop_end = suffixCl.position[it]+length; + } else { + if(drop_end !=0 && ( (drop_end - drop_begin) >= min_inst_length ) ) { + // drop node at x position + for(unsigned i = drop_begin; i < drop_end; i++) + filteredNodeIndexes.insert(i); + } + drop_begin = 0; + drop_end = 0; + } + prevPos = it; + } + + if(drop_end !=0 && ( (drop_end - drop_begin) >= min_inst_length ) ) { + // drop node at x position + for(unsigned i = drop_begin; i < drop_end; i++) + filteredNodeIndexes.insert(i); + } + } + }; + + + void DuplicatedCodeMiner::patternFilter() { + if(config.patternMaxSingleLength == 0 || config.patternMinFullLength == 0) + return; + + auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("patternFilter()"); + + common::timestat time = common::getProcessUsedTime(); + Sequence sequence(serializationData.nodeKindSequence); + ProcessPatternFilter ppf; + ppf.sequence = &sequence; + ppf.min_inst_length = config.patternMinFullLength; + ppf.dcm = this; + + LinearSuffixArray suffixArray(sequence); + LinearSuffixArray::Duplicateiterator lduplicateIterator = suffixArray.iterator(1, config.patternMaxSingleLength, config.patternMinFullLength, false); + + + lduplicateIterator.run(ppf); + size_t count = ppf.filteredNodeIndexes.size(); + + auto filterTime = common::getProcessUsedTime().user - time.user; + common::WriteMsg::write(CMSG_NODE_FILTERED_OUT, count, filterTime); + + config.stat.filterTime += filterTime; + + + perfSectionHandler.addTimeStamp("remove filtered nodes"); + + updateMemoryStat(config); + if(count > 0) + { + // make unique nodekinds for the filtered nodes + for (size_t i = 0; i < serializationData.nodeKindSequence.size(); ++i) + { + if (ppf.filteredNodeIndexes.find(i) != ppf.filteredNodeIndexes.end()) + { + serializationData.nodeKindSequence[i] = theCloneVisitor->getSeparator(); + delete serializationData.nodeInfoSequence[i]; + serializationData.nodeInfoSequence[i] = nullptr; + } + } + updateMemoryStat(config); + } + common::WriteMsg::write(CMSG_SERIALIZED_AST_SIZE, serializationData.nodeKindSequence.size()); + +/* + // DEBUG + for (auto nk : serializationData.nodeKindSequence) + printf("%d ", nk); + printf("\n"); +*/ + } + + void DuplicatedCodeMiner::dumpNodeIdSequence(const std::string filename) + { + ofstream out; + out.open(filename, ios::out | ios::trunc); + + unsigned indent_size = 0; + if(out.is_open()) + { + for(auto node : serializationData.nodeInfoSequence) + { + if(node) + { + for(unsigned i = 0; i < indent_size; ++i){ + out << " "; + } + out << node->getStringPath() << " : " << node->getLine() << ":" << node->getCol() << " | " << node->getEndLine() << ":" << node->getEndCol() << endl; + indent_size += 2; + }else{ + out << endl; + indent_size -= 2; + } + } + out.close(); + } + + } + + void DuplicatedCodeMiner::dumpNodeKindSequence(const std::string filename) + { + ofstream out; + out.open(filename); + int indent_size = 0; + if(out.is_open()) + { + for(auto kind : serializationData.nodeKindSequence) + { + if(kind == -2){ + indent_size -= 2; + } + for(int i = 0; i < indent_size; ++i){ + out << " "; + } + out << kind << endl; + + if(kind != -2) + indent_size += 2; + + } + out.close(); + } + } + + void DuplicatedCodeMiner::dumpCloneInstanceInformation() + { + vector instancesOfTheCurrentSystem = getInstancesOfaSystem(*currentSystem); + for (auto currentInsatnce : instancesOfTheCurrentSystem) + { + //get position of clone instance in the node id sequence + int pos = positions[currentInsatnce->getId()]; + + printf("CI:%d position:%d\n", currentInsatnce->getId(), pos); + printf(" Root Nodes:%s\n", currentInsatnce->getRootNodes().c_str()); + + //get the appropriate clone positioned object + auto cp = serializationData.nodeInfoSequence[pos]; + if (cp != nullptr) + { + printf("Path:%s TUPath:%s\n", cp->getStringPath().c_str(), cp->getStringTUPath().c_str()); + + } + } + } + + void DuplicatedCodeMiner::detectClones(std::map >& coveredNodes, std::set& needToSkip) + { + auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("detectClones()"); + + common::timestat time = common::getProcessUsedTime(); + + size_t sizeBeforePatternFilter, sizeAfterPatternFilter; + + do + { + sizeBeforePatternFilter = serializationData.nodeInfoSequence.size(); + common::WriteMsg::write(CMSG_USE_PATTERNFILTER); + patternFilter(); + sizeAfterPatternFilter = serializationData.nodeInfoSequence.size(); + } + while (sizeBeforePatternFilter != sizeAfterPatternFilter); + + config.stat.serializedASGLengthFiltered = serializationData.nodeInfoSequence.size(); + + common::WriteMsg::write(CMSG_DETECTING_CLONES); +/* + // DEBUG + printf("Serialized AST:\n"); + for (auto nk : serializationData.nodeKindSequence) + printf("%d ", nk); + printf("\n"); + + { + ofstream serializedFstream("Serialized.dat", std::ios_base::binary); + for (auto nk : serializationData.nodeKindSequence) + serializedFstream.write((char*)&nk, sizeof(nk)); + } +*/ + + + time = common::getProcessUsedTime(); + + std::map clone_counter; + Sequence sequence(serializationData.nodeKindSequence); + + LinearSuffixArray suffixArray(sequence); + common::WriteMsg::write(CMSG_CLONE_DETECTION_DONE_IN, common::getProcessUsedTime().user - time.user); + common::WriteMsg::write(CMSG_GENERATING_CLONE_INSTANCES); + + perfSectionHandler.addTimeStamp("clone detection"); + + time = common::getProcessUsedTime(); + LinearSuffixArray::Duplicateiterator lduplicateIterator = suffixArray.iterator( config.minAsgNodes, 0, 0, true); + + ProcessCC processCC; + + processCC.clone_counter = &clone_counter; + processCC.dcm = this; + processCC.maxCCSize = config.maxCCSize; + processCC.needToSkip = &needToSkip; + + + processCC.addFilter(std::make_shared(config.minOccur)); + processCC.addFilter(std::make_shared(config.minLines)); + processCC.addFilter(std::make_shared(*this)); + if (statementFilter) + processCC.addFilter(std::make_shared(*this)); + + + + lduplicateIterator.run(processCC); + + updateMemoryStat(config); + common::WriteMsg::write(CMSG_PROBALBLY_CLONES_FOUND); + processCC.buildCloneInstances(); + + common::WriteMsg::write(CMSG_DONE_IN, common::getProcessUsedTime().user - time.user); + + config.stat.cloneFindTime += common::getProcessUsedTime().user - time.user; + + + time = common::getProcessUsedTime(); + perfSectionHandler.addTimeStamp("clone instances"); + updateMemoryStat(config, "Clone instances are built"); + + //calculating coverage + if (config.metrics) + { + time = common::getProcessUsedTime(); + updateMemoryStat(config); + common::WriteMsg::write(CMSG_COMPUTING_COVERED_NODES); + computeCoveredNodes(); + perfSectionHandler.addTimeStamp("computeCoveredNodes"); + computeCoveredLines(); + perfSectionHandler.addTimeStamp("computeCoveredLines"); + updateMemoryStat(config); + common::WriteMsg::write(CMSG_DONE_D); + config.stat.calculateMetricsTime += common::getProcessUsedTime().user - time.user; + perfSectionHandler.addTimeStamp("clone coverage containers"); + } + } + + void DuplicatedCodeMiner::computeCoveredNodes() + { + for(genealogy::ListIterator cloneClassIt = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIt != currentSystem->getCloneClassesListIteratorEnd();++cloneClassIt) + { //clone class + const genealogy::CloneClass& cc = *cloneClassIt; + if (cc.getIsVirtual()) + continue; + unsigned int length = lengths[cc.getId()]; + for(genealogy::ListIterator cloneInstanceIt = cc.getItemsListIteratorBegin();cloneInstanceIt != cc.getItemsListIteratorEnd();++cloneInstanceIt) + { //clone instance + const genealogy::CloneInstance& ci = *cloneInstanceIt; + unsigned int pos = positions[ci.getId()]; + for(unsigned int i = 0; i < length; ++i) + { + const ASTNodeInfo* position = getNode(pos + i); + if(position) + { + const string componentName = getComponentName(position->getLimComponentId(),*limFact); + map >::iterator coverageIt = coveredNodes.find(componentName); + + if(coverageIt == coveredNodes.end()) + { + set nodeSet; + nodeSet.insert(position->getId()); + coveredNodes.insert(make_pair(componentName, nodeSet)); + } + else + { + (coverageIt->second).insert(position->getId()); + } + } + } + } //clone instances + } // clone classes + } + + void DuplicatedCodeMiner::computeCoveredLines() + { + for(genealogy::ListIterator cloneClassIt = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIt != currentSystem->getCloneClassesListIteratorEnd();++cloneClassIt) + { + const genealogy::CloneClass& cc = *cloneClassIt; + if (cc.getIsVirtual()) + continue; + + for(genealogy::ListIterator cloneInstanceIt = cc.getItemsListIteratorBegin();cloneInstanceIt != cc.getItemsListIteratorEnd();++cloneInstanceIt) + { + const genealogy::CloneInstance& ci = *cloneInstanceIt; + std::string path = ci.getPath(); + unsigned int pos = positions[ci.getId()]; + if (ci.getRootBegin() && serializationData.nodeInfoSequence[pos] ) + { + columbus::lim::asg::logical::Member& node = (columbus::lim::asg::logical::Member&)limFact->getRef((serializationData.nodeInfoSequence [pos]->getLimNodeId())); + + if ( columbus::lim::asg::Common::getIsClass(node) + || columbus::lim::asg::Common::getIsMethod(node) + || columbus::lim::asg::Common::getIsPackage(node) + || columbus::lim::asg::Common::getIsComponent(node)) + { + if (!node.getIsContainedInIsEmpty()) { + path = columbus::lim::asg::Common::getFullPath (*node.getIsContainedInListIteratorAssocBegin()); + } + } + } + LowerStringOnWindows(path); + Key fileId = limFact->getStringTable().set(path); + + for(unsigned int i = ci.getLine(); i <= ci.getEndLine(); ++i) + coveredLines.insert(LineIdentifier(fileId,i)); + } + } + } + + void DuplicatedCodeMiner::buildBaseCloneTree() + { + common::timestat time = common::getProcessUsedTime(); + common::WriteMsg::write(CMSG_BUILD_CLONE_TREE); + + columbus::genealogy::System& lastSystemRef = *currentSystem; + columbus::graph::Node cloneRootNode = graph.findNode(graphsupport::graphconstants::UID_CLONE_ROOT); + + for (auto groupsIter = lastSystemRef.getCloneClassesListIteratorBegin(); groupsIter != lastSystemRef.getCloneClassesListIteratorEnd(); ++groupsIter) + { // clone classes + auto& cc = const_cast(*groupsIter); + std::set componentsOfTheClass; // Container to store the components of all the corresponding clone instance nodes + + columbus::graph::Node classItem = graph.findNode(getGraphNameOfGenelogyNode(cc)); + if (classItem == columbus::graph::Graph::invalidNode) + { + classItem = graph.createNode(getGraphNameOfGenelogyNode(cc), columbus::graph::Node::NodeType(graphsupport::graphconstants::NTYPE_DCF_CLONECLASS)); + graph.createDirectedEdge(cloneRootNode, classItem, graphsupport::graphconstants::ETYPE_DCF_CLONETREE, true); + } + + // first deal with clone instances + for (auto itemsIter = cc.getItemsListIteratorBegin(); itemsIter != cc.getItemsListIteratorEnd(); ++itemsIter) + { + auto& ci = const_cast(*itemsIter); + std::list nodes; + + columbus::graph::Node instanceItem = graph.findNode(getGraphNameOfGenelogyNode(ci)); + if(instanceItem == columbus::graph::Graph::invalidNode) + { + instanceItem = graph.createNode(getGraphNameOfGenelogyNode(ci), columbus::graph::Node::NodeType(graphsupport::graphconstants::NTYPE_DCF_CLONEINSTANCE)); + graph.createDirectedEdge(classItem, instanceItem, graphsupport::graphconstants::ETYPE_DCF_CLONETREE, true); + columbus::graphsupport::addPositionAttribute(graph, instanceItem, ci.getPath(), ci.getLine(), ci.getCol(), ci.getEndLine(), ci.getEndCol()); + } + + std::map >::iterator itLimNodes = limNodeCloneInstanceMap.find(ci.getId()); + std::map >::iterator itLimComponent = limComponentCloneInstanceMap.find(ci.getId()); + + if (itLimNodes != limNodeCloneInstanceMap.end()) + { + std::set& nodes = itLimNodes->second; + for (auto LimNodeId : nodes) + { + std::string gaphNodeUUid = columbus::lim2graph::VisitorGraphConverter::determineNodeName(limFact->getRef(LimNodeId)); + columbus::graph::Node theItem = graph.findNode(gaphNodeUUid); + if (theItem != columbus::graph::Graph::invalidNode) + graph.createDirectedEdge(theItem, instanceItem, graphsupport::graphconstants::ETYPE_DCF_HASCLONE, true); + else + { + common::WriteMsg::write(WriteMsg::mlWarning, "The source code element (uuid: %s) is not found for clone instance (id: %d)!\n", gaphNodeUUid.c_str(), ci.getId()); + } + } + } + + // Create the component edges of the clone instance nodes + if (itLimComponent != limComponentCloneInstanceMap.end()) + { + const std::set& componentsOfTheInstance = itLimComponent->second; + for (auto componentId : componentsOfTheInstance) + { + std::string gaphNodeUUid = columbus::lim2graph::VisitorGraphConverter::determineNodeName(limFact->getRef(componentId)); + columbus::graph::Node theCommponent = graph.findNode(gaphNodeUUid); + if (theCommponent != columbus::graph::Graph::invalidNode) + graph.createDirectedEdge(instanceItem, theCommponent, graphsupport::graphconstants::ETYPE_LIM_COMPONENT, true); + else + { + common::WriteMsg::write(WriteMsg::mlWarning,"The commponent (uuid: %s) is not found for clone instance %d (id: %d)!\n", gaphNodeUUid.c_str(), ci.getId()); + } + } + + // Adding the components of the instance to the component set of the clone class + componentsOfTheClass.insert(componentsOfTheInstance.begin(), componentsOfTheInstance.end()); + } + } //loop clone instance + + // deal with clone classes + // Create the component edges of the clone class nodes + for (auto componentId : componentsOfTheClass) + { + std::string gaphNodeUUid = columbus::lim2graph::VisitorGraphConverter::determineNodeName(limFact->getRef(componentId)); + columbus::graph::Node theComponent = graph.findNode(gaphNodeUUid); + graph.createDirectedEdge(classItem, theComponent, graphsupport::graphconstants::ETYPE_LIM_COMPONENT, true); + } + } + + common::WriteMsg::write(CMSG_DONE_D); + config.stat.buildCloneTreeTime += common::getProcessUsedTime().user - time.user; + } + + std::vector DuplicatedCodeMiner::getInstanceIds(const genealogy::CloneInstance& ci) { + vector instanceRootIds; + + unsigned int length = ci.getRootLength(); + if(length == 1) { + instanceRootIds.push_back(ci.getRootBegin()); + } else { + stringstream inputStreamOfInstances(ci.getRootNodes()); + char buffer [11] = "0x00000000"; + while (inputStreamOfInstances.get(buffer+2,9)) { + std::istringstream in(buffer); + NodeId nodeid ; + in >>std::hex >>nodeid; + instanceRootIds.push_back(nodeid); + } + } + return instanceRootIds; + } + + + int DuplicatedCodeMiner::serializeAsg(bool createComponent) + { + auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("serializeAsg()"); + + common::timestat serializeTime = common::getProcessUsedTime(); + int exit_code = EXIT_SUCCESS; + + serializationData.nodeKindSequence.clear(); + clearNodeIdSequence(serializationData.nodeInfoSequence); + serializationData.referencesMap.clear(); + serializationData.inverseReferencesMap.clear(); + + + delete theCloneVisitor; + theCloneVisitor = new CppCloneVisitor(limOrigin, limFact); + + theCloneVisitor->setFilterLogStream(filterOut); + + //TODO : fileNamesByComponent üres... + if (createComponent) { + theCloneVisitor->setFileNamesByComponent(&fileNamesByComponent); + theCloneVisitor->setTuPathToCompAndTuId(&tuPathToCompAndTuId); + } else { + theCloneVisitor->setFileNamesByComponent(NULL); + } + + double numberOfComponents = config.files.size(); + int componentCounter = 0; + for (auto& componentFileName : config.files) + { + ++componentCounter; + std::string componenetID = componentFileName.c_str(); + + if (createComponent) { + // create component to genealogy + columbus::genealogy::Component* componentRef=genealogyFact->createComponentNode(); + componentRef->setLocation(componentFileName); + componentRef->setName(componenetID); + currentSystem->addComponents(componentRef); + //calculate hash + //std::size_t hash = currentFactory.calculateHash(currentFactory.operator ()(fname), fname); + //componentRef->setCode(hash); + } + NodeId limComponentId = getLimComponenetIdByName(componenetID,*limFact); + list compilationUnitsList; + loadStringListFromFile(componentFileName, compilationUnitsList); + + compilationUnitsList.remove_if([](const string& fileName) { return common::pathFindExtension(fileName) != "ast"; }); + + common::WriteMsg::write(CMSG_LOADING_CPP_COMPONENT, componentCounter / numberOfComponents, compilationUnitsList.size(), componentFileName.c_str()); + common::WriteMsg::write(CMSG_CURRENT_COMPONENT_ID, limComponentId); + + //filter + std::map >::iterator it = filteredNodes.find(componenetID); + if(it != filteredNodes.end()) { + theCloneVisitor->setFilter(it->second); + } else { + theCloneVisitor->clearFilter(); + } + theCloneVisitor->resetVisitedNodesNumber(); + theCloneVisitor->setCurrentLimComponent(limComponentId); + theCloneVisitor->serializeComponent(compilationUnitsList, serializationData); + + serializedAsgNodeNumberByComponenet[componenetID] = theCloneVisitor->getVisitedNodesNumber(); + config.stat.totalASTNodeNumber += theCloneVisitor->getVisitedNodesNumber(); + updateMemoryStat(config, "Component Loaded"); + +/* + // Debug + printf("Sizes referencesMap: %lu\n", serializationData.referencesMap.size()); + size_t sum = 0; + for (const auto& m : serializationData.referencesMap) + sum += m.second.size(); + printf(" maps sum: %lu\n", sum); + + printf("Sizes nodeReferencePathMap: %lu\n", serializationData.nodeReferencePathMap.size()); + sum = 0; + for (const auto& m : serializationData.nodeReferencePathMap) + sum += m.second.size(); + printf(" maps sum: %lu\n", sum); +*/ + +/* + // Debug + printf("Last separator: %d\n", theCloneVisitor->getSeparator()); +*/ + } + + config.stat.asgSerializationTime += common::getProcessUsedTime().user - serializeTime.user; + return exit_code; + } + + int DuplicatedCodeMiner::dcminer() { + bool errorAtLoad = false; + + auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("dcminer()"); + + //creating the genealogy graph + genealogy::Project& genealogyBase = initGenealogy(errorAtLoad); + updateMemoryStat(config); + set needToSkip; + + int exit_code = EXIT_SUCCESS; + + if (!initLim()) + return EXIT_FAILURE; + + updateMemoryStat(config); + + + bool first = false; + do { + // first we need to reset the state of the objects below (in case that DCF is being executed for the second time) + first=!first; + + needToSkip.clear(); + coveredNodes.clear(); + coveredLines.clear(); + cloneClassMap.clear(); + + genealogyFact->enableReverseEdges(); + int age = currentSystem->getAge(); + genealogyFact->destroyNode(currentSystem->getId()); + currentSystem = createSystem(); + + currentSystem->setAge(age); + updateMemoryStat(config); + + limFact->turnFilterOn(); + + exit_code = serializeAsg(true); + config.stat.serializedASGLength = serializationData.nodeInfoSequence.size(); + +/* + // Debug + printf("Serialized AST:\n"); + for (const auto& n: serializationData.nodeInfoSequence) + { + if (n) + { + n->dump(); + const auto& refmap = serializationData.referencesMap[n->getTUPath()]; + auto it = refmap.find(n->getId()); + if (it != refmap.end()) + printf("REF: %d\n", it->second); + } + } +*/ + // generate inverse references from the referencesMap + for (const auto& ASTRefInfo : serializationData.referencesMap) + for (const auto& reference : ASTRefInfo.second) + serializationData.inverseReferencesMap[ASTRefInfo.first][reference.second].push_back(reference.first); + +/* + // Debug + printf("Reference map:\n"); + for (const auto& ASTRefInfo : serializationData.referencesMap) + { + printf("AST:%s\n", ASTNodeInfo::getStringPath(ASTRefInfo.first).c_str()); + for (const auto& reference : ASTRefInfo.second) + printf(" %u -> %u\n", reference.first, reference.second); + } + + // Debug + printf("Inverse reference map:\n"); + for (const auto& ASTRefInfo : serializationData.inverseReferencesMap) + { + printf("AST:%s\n", ASTNodeInfo::getStringPath(ASTRefInfo.first).c_str()); + for (const auto& reference : ASTRefInfo.second) + { + printf(" %u -> ", reference.first); + for (const auto& ref : reference.second) + printf("%u ", ref); + printf("\n"); + } + } + // Debug + printf("Reference map:\n"); + for (const auto& ASTRefInfo : serializationData.referencesMap) + { + printf("AST:%s\n", ASTNodeInfo::getStringPath(ASTRefInfo.first).c_str()); + for (const auto& reference : ASTRefInfo.second) + printf(" %s -> %s\n", ASTNodeInfo::getStringPath(serializationData.nodeReferencePathMap[ASTRefInfo.first][reference.first]).c_str() + , ASTNodeInfo::getStringPath(serializationData.nodeReferencePathMap[ASTRefInfo.first][reference.second]).c_str()); + } + +*/ + +/* + // Debug + printf("Sizes referencesMap: %lu\n", serializationData.referencesMap.size()); + size_t sum = 0; + for (const auto& m : serializationData.referencesMap) + sum += m.second.size(); + printf(" maps sum: %lu\n", sum); + + printf("Sizes inverseReferencesMap: %lu\n", serializationData.inverseReferencesMap.size()); + + sum = 0; + int oneref = 0; + int multipleref = 0; + for (const auto& m : serializationData.inverseReferencesMap) + { + sum += m.second.size(); + for (const auto& s : m.second) + { + if (s.second.size() == 1) + ++oneref; + else + ++multipleref; + } + } + + printf(" number of sets: %lu\n 1: %d\n *: %d\n", sum, oneref, multipleref); + + printf("Sizes nodeReferencePathMap: %lu\n", serializationData.nodeReferencePathMap.size()); + sum = 0; + for (const auto& m : serializationData.nodeReferencePathMap) + sum += m.second.size(); + printf(" maps sum: %lu\n", sum); +*/ + detectClones(coveredNodes, needToSkip); + updateMemoryStat(config); + + if (config.maxCCSize) { + for (const auto& needToSkipFile :needToSkip) + { + if (needToSkipFile.empty()) + continue; + + common::WriteMsg::write(CMSG_ADDING_PATH_TO_FILTER, needToSkipFile.c_str()); + config.bpaths.push_back(needToSkipFile); + } + } + + } while (config.maxCCSize && needToSkip.size()>0 && first); + + + updateMemoryStat(config); + columbus::lim2graph::convertBaseGraph(*limFact, graph, true, true, /*components=*/ true, /*variants=*/ true); + //cout << "Graph converting took: " << common::getProcessUsedTime().user - time.user << endl; + + updateMemoryStat(config); + columbus::graph::Node cloneRootNode = graph.createNode(graphsupport::graphconstants::UID_CLONE_ROOT, columbus::graph::Node::NodeType(graphsupport::graphconstants::NTYPE_ROOT)); + graphsupport::addNodeNameAttribute(graph, cloneRootNode,graphsupport::graphconstants::UID_CLONE_ROOT); + graphsupport::addNodeLongNameAttribute(graph, cloneRootNode,graphsupport::graphconstants::UID_CLONE_ROOT); + + updateMemoryStat(config); + buildBaseCloneTree(); + perfSectionHandler.addTimeStamp("buildBaseCloneTree"); + + + if (config.metrics) + calculateMetrics(); + + updateMemoryStat(config); + + //generating evolution mapping + if(!errorAtLoad && !config.genealogyFilename.empty()) + { + evolutionMapping(*currentSystem, genealogyBase); + } + + setClonesUniqueNameAndCloneSmells(); + + // turn on graph indexer and build index + indexer = &columbus::graphsupport::GraphRangeIndexer::getGraphRangeIndexerInstance(); + indexer->turnOn(graph); + + if (config.metrics) + { + calculateEvolutionDependentMetrics(); + addDefaultMetricsForTheNodes(); + } + clearNodeIdSequence(serializationData.nodeInfoSequence); + serializationData.nodeKindSequence.clear(); + + return exit_code; + } + + void DuplicatedCodeMiner::addDefaultMetricsForTheNodes() + { + std::map> nodeTypeMetricMap; + std::vector metrics; + + rulHandler->getRuleIdList(metrics); + + for (const auto& metric : metrics) + for (const auto& Item : rulHandler->getCalculatedForSet(metric)) + nodeTypeMetricMap[Item].insert(metric); +/* + // DEBUG + for (const auto& item : nodeTypeMetricMap) + { + printf("Item:%s\n", item.first.c_str()); + for (const auto& metric: item.second) + { + printf(" Metric:%s\n", metric.c_str()); + } + } +*/ + auto nodeIt = graph.getNodes(); + while (nodeIt.hasNext()) + { + auto node = nodeIt.next(); + auto nodeMapIt = nodeTypeMetricMap.find(node.getType().getType()); + if (nodeMapIt != nodeTypeMetricMap.end()) + { +/* + // DEBUG + printf("Node:%s Type:%s\n", node.getUID().c_str(), node.getType().getType().c_str()); +*/ + + + if (graphsupport::getRealizationLevel(node) == graphsupport::graphconstants::ATTRVALUE_LIM_RELDECLARES) + { + for (const auto& metric : nodeMapIt->second) + { + auto attributeIterator = node.findAttributeByName(metric); + if (!attributeIterator.hasNext()) + graphsupport::setMetricINVALID(graph, node, metric); + } + + } + else + { + for (const auto& metric : nodeMapIt->second) + { + auto attributeIterator = node.findAttributeByName(metric); + if (!attributeIterator.hasNext()) + { + // The metric is missing from the node + if ((metric == "CA") && getIsNeeded(metric)) + graphsupport::setMetricInt(graph, node, "CA", 0); + + else if ((metric == "CCL") && getIsNeeded(metric)) + graphsupport::setMetricInt(graph, node, "CCL", 0); + + else if ((metric == "CCO") && getIsNeeded(metric)) + graphsupport::setMetricInt(graph, node, "CC", 0); + + else if ((metric == "CC") && getIsNeeded(metric)) + graphsupport::setMetricFloat(graph, node, "CC", 0.0); + + else if ((metric == "CEE") && getIsNeeded(metric)) + graphsupport::setMetricFloat(graph, node, "CEE", 0.0); + + else if ((metric == "CEG") && getIsNeeded(metric)) + graphsupport::setMetricFloat(graph, node, "CEG", 0.0); + + else if ((metric == "CE") && getIsNeeded(metric)) + graphsupport::setMetricFloat(graph, node, "CE", 0.0); + + else if ((metric == "CI") && getIsNeeded(metric)) + graphsupport::setMetricInt(graph, node, "CI", 0); + + else if ((metric == "CLC") && getIsNeeded(metric)) + graphsupport::setMetricFloat(graph, node, "CLC", 0.0); + + else if ((metric == "CLLOC") && getIsNeeded(metric)) + graphsupport::setMetricInt(graph, node, "CLLOC", 0); + + else if ((metric == "CLLC") && getIsNeeded(metric)) + graphsupport::setMetricInt(graph, node, "CLLC", 0); + + else if ((metric == "CR") && getIsNeeded(metric)) + graphsupport::setMetricFloat(graph, node, "CR", 0.0); + + else if ((metric == "CV") && getIsNeeded(metric)) + graphsupport::setMetricFloat(graph, node, "CV", 0.0); + + else if ((metric == "LDC") && getIsNeeded(metric)) + graphsupport::setMetricInt(graph, node, "LDC", 0); + + else if ((metric == "LLDC") && getIsNeeded(metric)) + graphsupport::setMetricInt(graph, node, "LLDC", 0); + + else if ((metric == "NCR") && getIsNeeded(metric)) + graphsupport::setMetricFloat(graph, node, "NCR", 0.0); + + } + } + } + } + } + + + } + + columbus::genealogy::System* DuplicatedCodeMiner::createSystem() { + columbus::genealogy::System* system= genealogyFact->createSystemNode(); + system->setName(config.systemName); + system->setVersion(config.systemVersion); + system->setLimFileLocation(config.limFileName); + system->setAge(1); + genealogyFact->getRoot()->addSystems(system->getId()); + return system; + } + + columbus::genealogy::Project& DuplicatedCodeMiner::initGenealogy(bool& errorAtLoad) { + common::WriteMsg::write(CMSG_INITIALIZING_GENEALOGY); + + errorAtLoad = false; + + strTable = new RefDistributorStrTable(); + genealogyFact = new columbus::genealogy::Factory(*strTable); + + if (!config.genealogyFilename.empty()) { + boost::filesystem::path genealogyFile(config.genealogyFilename); + try { + if (boost::filesystem::exists(genealogyFile)) { + columbus::CsiHeader header; + genealogyFact->load(config.genealogyFilename, header); + // We should replace the string table to reset the internal bucket counters due to the enormous amount of delete operations + columbus::RefDistributorStrTable* newStrTable = new RefDistributorStrTable(); + genealogyFact->swapStringTable(*newStrTable); + delete strTable; + strTable = newStrTable; + } + } catch (columbus::genealogy::GenealogyException& e) { + common::WriteMsg::write(CMSG_GENALOGY_WILL_NOT_BE_SAVED, e.toString().c_str()); + errorAtLoad = true; + } + } + + if(errorAtLoad) { + delete genealogyFact; + delete strTable; + strTable = new RefDistributorStrTable(); + genealogyFact = new columbus::genealogy::Factory(*strTable); + } + + columbus::genealogy::Project& genealogyBase= *genealogyFact->getRoot(); + + for ( columbus::genealogy::ListIterator systemsIterator=genealogyBase.getSystemsListIteratorBegin(); systemsIterator !=genealogyBase.getSystemsListIteratorEnd(); ++systemsIterator) { + lastSystem = &*systemsIterator; + } + + currentSystem = createSystem(); + if ( lastSystem ) { + currentSystem->setPrev(lastSystem->getId()); + currentSystem->setAge(lastSystem->getAge()+1); + } else { + currentSystem->setAge(1); + } + + common::WriteMsg::write(CMSG_DONE_D); + return genealogyBase; + } + + + void DuplicatedCodeMiner::evolutionMapping(columbus::genealogy::System& systemRef, columbus::genealogy::Project& genealogyBase) { + // load back asg for evolution mapping + common::timestat time = common::getProcessUsedTime(); + + common::WriteMsg::write(CMSG_START_EVOLUTION_MAPPING); + updateMemoryStat(config); + + + vector instancesOfTheCurrentSystem = getInstancesOfaSystem(systemRef); + unsigned numberOfInstancesInTheRefSystem = instancesOfTheCurrentSystem.size(); + //Sort instances by translation unit id + std::sort(instancesOfTheCurrentSystem.begin(), instancesOfTheCurrentSystem.end(), [this](genealogy::CloneInstance* struct1, genealogy::CloneInstance* struct2){ + return ( tuPathToCompAndTuId[ciIdToAST[struct1->getId()]].second < tuPathToCompAndTuId[ciIdToAST[struct2->getId()]].second ); + }); + + std::sort(instancesOfTheCurrentSystem.begin(), instancesOfTheCurrentSystem.end(), sortCloneInstancesByComponentId()); + + // calculate the similarity attributes for all instances + for (vector::iterator currentInsatnceIt = instancesOfTheCurrentSystem.begin(); currentInsatnceIt != instancesOfTheCurrentSystem.end();++currentInsatnceIt) { + genealogy::CloneInstance* instanceOfTheCurentSystem = *currentInsatnceIt; + + computeSimilarityAttributes(*instanceOfTheCurentSystem); + } + + + updateMemoryStat(config); + if (lastSystem) { + currentSystem->setPrev(lastSystem->getId()); + ((columbus::genealogy::System*)lastSystem)->setNext(currentSystem->getId()); + + vector instancesOfTheLastSystem = getInstancesOfaSystem(*lastSystem); + unsigned numberOfInstancesInTheLastSystem = instancesOfTheLastSystem.size(); + config.stat.numberOfInstancesInTheLastSystem = numberOfInstancesInTheLastSystem; + + for (vector::iterator currentInsatnceIt = instancesOfTheCurrentSystem.begin(); currentInsatnceIt != instancesOfTheCurrentSystem.end();++currentInsatnceIt) { + genealogy::CloneInstance* instanceOfTheCurentSystem = *currentInsatnceIt; + + if (!instanceOfTheCurentSystem->getPrevIsEmpty() || instanceOfTheCurentSystem->getIsVirtual()) + continue; + + for (vector::iterator prevInsatnceIt = instancesOfTheLastSystem.begin(); prevInsatnceIt != instancesOfTheLastSystem.end();++prevInsatnceIt) { + genealogy::CloneInstance* instanceOfTheLastSystem = *prevInsatnceIt; + + if (!instanceOfTheLastSystem->getNextIsEmpty() || instanceOfTheLastSystem->getIsVirtual()) + continue; + + double sim=similarity(*instanceOfTheLastSystem, *instanceOfTheCurentSystem); + common::WriteMsg::write(WriteMsg::mlDDDDebug, "Similarity of %d(last) and %d(current): %f\n", instanceOfTheLastSystem->getId(), instanceOfTheCurentSystem->getId(), sim); + if (sim==0.0) { + instanceOfTheLastSystem->addNext(instanceOfTheCurentSystem); + instanceOfTheCurentSystem->addPrev(instanceOfTheLastSystem); + trivial_pairs++; + break; + } + } + } + + config.stat.numberOfTrivialPairs = trivial_pairs; + try{ + boost::numeric::ublas::matrix m(numberOfInstancesInTheLastSystem - trivial_pairs, numberOfInstancesInTheRefSystem - trivial_pairs); + + for (unsigned int q1=0; q1::infinity(); + } + } + + updateMemoryStat(config); + + unsigned int row=0; + unsigned int col=0; + typedef boost::bimap IntCloneInstanceBimap; + typedef std::map IntCloneInstanceMap; + + IntCloneInstanceMap row_map; + IntCloneInstanceBimap col_map; + + for (vector::iterator prevInsatnceIt = instancesOfTheLastSystem.begin(); prevInsatnceIt != instancesOfTheLastSystem.end();++prevInsatnceIt) { + genealogy::CloneInstance* instanceOfTheLastSystem = *prevInsatnceIt; + + if (!instanceOfTheLastSystem->getNextIsEmpty() || instanceOfTheLastSystem->getIsVirtual()) + continue; + + row_map.insert(IntCloneInstanceMap::value_type(row, instanceOfTheLastSystem)); + + for (vector::iterator currentInsatnceIt = instancesOfTheCurrentSystem.begin(); currentInsatnceIt != instancesOfTheCurrentSystem.end();++currentInsatnceIt) { + genealogy::CloneInstance* instanceOfTheCurentSystem = *currentInsatnceIt; + + if (!instanceOfTheCurentSystem->getPrevIsEmpty() || instanceOfTheCurentSystem->getIsVirtual()) + continue; + + IntCloneInstanceBimap::right_iterator leftIter=col_map.right.find(instanceOfTheCurentSystem); + unsigned int mycol = 0; + if (leftIter != col_map.right.end()) + mycol = leftIter->second; + else { + col_map.insert(IntCloneInstanceBimap::value_type(col, instanceOfTheCurentSystem)); + mycol = col; + col++; + } + double sim = similarity(*instanceOfTheLastSystem, *instanceOfTheCurentSystem); // Ez mar egyszer ki lett szamolva! Lehet el kellene tarolni es nem megegyszer kiszamolni. + m(row, mycol) = sim; + } + row++; + } + + updateMemoryStat(config); + boost::numeric::ublas::matrix m_orig(m); + + common::math::HungarianMethod Hm(m_orig); + std::map solution=Hm.solve(common::math::HungarianMethod::INJECTIVE_KIND); + std::map::iterator sol_iter=solution.begin(); + unsigned int nontrivial_maps=0; + double overall_similarity=0.0; + while (sol_iter!=solution.end()) { + unsigned int second=(*sol_iter).first; + unsigned int first=(*sol_iter).second; + sol_iter++; + if (first>=m.size1() || second>=m.size2() || m(first,second)==numeric_limits::infinity()) + continue; + IntCloneInstanceMap::iterator iter1; + if ((iter1=row_map.find(first))==row_map.end()) + continue; + IntCloneInstanceBimap::left_iterator iter2; + if ((iter2=col_map.left.find(second))==col_map.left.end()) + continue; + (*iter1).second->addNext((*iter2).second->getId()); + (*iter2).second->addPrev((*iter1).second->getId()); + nontrivial_maps++; + overall_similarity+=m(first, second); + } + } + catch (std::bad_alloc&) + { + common::WriteMsg::write(CMSG_NOT_ENOUGH_MEMORY_TO_EVOLUTE); + } + // connecting clone classes + + // connect by fingerprints + std::map prevFingerprints; + for (columbus::genealogy::ListIterator it = lastSystem->getCloneClassesListIteratorBegin(); it != lastSystem->getCloneClassesListIteratorEnd();++it ) { + columbus::genealogy::CloneClass& classItem = const_cast(*it); + + if(classItem.getIsVirtual()) + continue; + + prevFingerprints.insert(make_pair(classItem.getFingerprintKey(), &classItem)); + } + + for (columbus::genealogy::ListIterator it = currentSystem->getCloneClassesListIteratorBegin(); it != currentSystem->getCloneClassesListIteratorEnd();++it ) { + columbus::genealogy::CloneClass& classItem = const_cast(*it); + + if(classItem.getIsVirtual()) + continue; + + std::map::const_iterator fpIt = prevFingerprints.find(classItem.getFingerprintKey()); + if (fpIt != prevFingerprints.end()) { + columbus::genealogy::CloneClass& candClass = *fpIt->second; + if (classItem.getPrevIsEmpty() && candClass.getNextIsEmpty()) { + classItem.addPrev(candClass.getId()); + candClass.addNext(classItem.getId()); + } + } + } + + // connect by instances + columbus::genealogy::System& lastSystemRef=(columbus::genealogy::System&)*currentSystem; + + for (columbus::genealogy::ListIterator groupIter=lastSystemRef.getCloneClassesListIteratorBegin();groupIter!=lastSystemRef.getCloneClassesListIteratorEnd();++groupIter) { + columbus::genealogy::CloneClass& classItem= const_cast(*groupIter); + + //Virtual Node-ok miatt javitva. + if (!classItem.getPrevIsEmpty() || classItem.getIsVirtual()) + continue; + + std::map countMap; + for(columbus::genealogy::ListIterator itemsIter=classItem.getItemsListIteratorBegin();itemsIter!=classItem.getItemsListIteratorEnd();++itemsIter) { + columbus::genealogy::CloneInstance& itm= const_cast(*itemsIter); + //Virtual Node-ok miatt javitva. + if(itm.getIsVirtual()) + continue; + + + for(columbus::genealogy::ListIterator prevIt = itm.getPrevListIteratorBegin();prevIt != itm.getPrevListIteratorEnd();++prevIt) { + columbus::NodeId prev=prevIt->getId(); + if (genealogyFact->getExist(prev)) { + columbus::genealogy::CloneInstance& prevRef=(columbus::genealogy::CloneInstance&)genealogyFact->getRef(prev); + columbus::NodeId groupId=prevRef.getCloneClass()->getId(); + if(groupId != 0){ + std::map::iterator iter=countMap.find(groupId); + if (iter==countMap.end()) { + countMap.insert(std::map::value_type(groupId, 1)); + } else + (*iter).second++; + } + } + } + } + + + std::map::iterator iter=countMap.begin(); + columbus::NodeId maxId=0; + unsigned int maxValue=0; + while (iter!=countMap.end()) { + unsigned int currentValue=(*iter).second; + if (currentValue>maxValue) { + maxValue=currentValue; + maxId=(*iter).first; + } + iter++; + } + if (maxValue>0) { + columbus::genealogy::CloneClass& candClass=(columbus::genealogy::CloneClass&)genealogyFact->getRef(maxId); + if (maxValue>classItem.getItemsSize()/2 && maxValue>candClass.getItemsSize()/2) { + //connecting the classes + if (classItem.getPrevIsEmpty() && candClass.getNextIsEmpty()) { + classItem.addPrev(candClass.getId()); + candClass.addNext(classItem.getId()); + } + } + } + } + + for(std::map::iterator serializedAsgMapIt = serializedAsgMap.begin(); serializedAsgMapIt != serializedAsgMap.end(); ++serializedAsgMapIt) { + clearNodeIdSequence(serializedAsgMapIt->second.nodeInfoSequence); + } + serializedAsgMap.clear(); + common::WriteMsg::write(CMSG_DONE_D); + + } + + updateMemoryStat(config); + + config.stat.evolutionMappingTime = common::getProcessUsedTime().user - time.user; + common::WriteMsg::write(WriteMsg::mlDebug, "Debug: Evolution mapping took %d (1/100s)\n", config.stat.evolutionMappingTime); + } + + + void DuplicatedCodeMiner::setClonesUniqueNameAndCloneSmells() + { + auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("setClonesUniqueNameAndCloneSmells()"); + common::timestat time = common::getProcessUsedTime(); + + unsigned uniqueId = 0; + if (lastSystem != NULL) + uniqueId = lastSystem->getFirstFreeID(); + + columbus::genealogy::System& currentSystemRef=*currentSystem; + for (auto classItemsIter = currentSystemRef.getCloneClassesListIteratorBegin(); classItemsIter != currentSystemRef.getCloneClassesListIteratorEnd(); ++classItemsIter) + { + columbus::genealogy::CloneClass& classItem = const_cast(*classItemsIter); + if (classItem.getIsVirtual()) + continue; + + const columbus::genealogy::CloneClass* prevClass = &classItem; + + if (!classItem.getPrevIsEmpty()) + { + columbus::genealogy::ListIterator prevIter = classItem.getPrevListIteratorEnd() ; + --prevIter; + prevClass = dynamic_cast(&(*prevIter)); + } + + auto cloneClassGraphNode = graph.findNode(getGraphNameOfGenelogyNode(classItem)); + + //if the clone class is new + if (prevClass == &classItem) + { + std::string id = to_string(uniqueId++); + classItem.setUniqueName(id + "~CloneClass"); + + if (currentSystemRef.getAge() > 1) + { + classItem.setCloneSmellType(columbus::genealogy::cstAppearing); + } + + } + else + { + classItem.setUniqueName(prevClass->getUniqueName()); + + for(auto itemsIter = prevClass->getItemsListIteratorBegin(); itemsIter != prevClass->getItemsListIteratorEnd(); ++itemsIter) + { + columbus::genealogy::CloneInstance& cloneInstance = const_cast(*itemsIter); + if (itemsIter->getNextSize() == 0 && !cloneInstance.getIsVirtual()) + { + columbus::genealogy::CloneInstance* cloneInstanceNext = cloneInstance.getFactory().createCloneInstanceNode(); + cloneInstanceNext->setCloneClass(&classItem); + cloneInstanceNext->setIsVirtual(true); + cloneInstanceNext->setUniqueNameKey(cloneInstance.getUniqueNameKey()); + cloneInstanceNext->setCloneSmellType(columbus::genealogy::cstDisappearing); + cloneInstanceNext->addPrev(cloneInstance.getId()); + cloneInstanceNext->setPath(cloneInstance.getPath()); + cloneInstanceNext->setLine(cloneInstance.getLine()); + cloneInstanceNext->setEndLine(cloneInstance.getEndLine()); + cloneInstanceNext->setCol(cloneInstance.getCol()); + cloneInstanceNext->setEndCol(cloneInstance.getEndCol()); + + cloneInstance.addNext(cloneInstanceNext); + classItem.addItems(cloneInstanceNext); + + auto cloneInstanceGraphNode = graph.createNode(getGraphNameOfGenelogyNode(*cloneInstanceNext), columbus::graph::Node::NodeType(graphsupport::graphconstants::NTYPE_DCF_CLONEINSTANCE)); + graph.createDirectedEdge(cloneClassGraphNode, cloneInstanceGraphNode, graphsupport::graphconstants::ETYPE_DCF_CLONETREE, true); + columbus::graphsupport::addPositionAttribute(graph, cloneInstanceGraphNode, cloneInstance.getPath(), cloneInstance.getLine(), cloneInstance.getCol(), cloneInstance.getEndLine(), cloneInstance.getEndCol()); + } + } + } + + graphsupport::addNodeNameAttribute(graph, cloneClassGraphNode, classItem.getUniqueName()); + graphsupport::setStringAttribute(graph, cloneClassGraphNode, graphsupport::graphconstants::ATTR_DCF_CLONESMELLTYPE, genealogy::Common::toString(classItem.getCloneSmellType())); + + // Set the clone smells of the clone instances + for (auto itemsIter = classItemsIter->getItemsListIteratorBegin(); itemsIter != classItemsIter->getItemsListIteratorEnd(); ++itemsIter) + { + columbus::genealogy::CloneInstance& instance = const_cast(*itemsIter); + + auto cloneInstanceGraphNode = graph.findNode(getGraphNameOfGenelogyNode(instance)); + if (instance.getPrevIsEmpty()) + { + std::string id = to_string(uniqueId++); + instance.setUniqueName(id + "~CloneInstance"); + + if (classItem.getCloneSmellType() == columbus::genealogy::cstNone) + if (!instance.getCloneClass()->getPrevIsEmpty()) + instance.setCloneSmellType(columbus::genealogy::cstAppearing); + } + else + { + if (!instance.getIsVirtual()) + { + const columbus::genealogy::CloneInstance& prev = dynamic_cast(*instance.getPrevListIteratorBegin()); + instance.setUniqueNameKey(prev.getUniqueNameKey()); + + if (classItem.getCloneSmellType() == columbus::genealogy::cstNone) + { + if (prev.getCloneClass()->getUniqueNameKey() == instance.getCloneClass()->getUniqueNameKey()) + { + instance.setCloneSmellType(columbus::genealogy::cstNone); + } + else + { + if (prev.getCloneClass()->getNextSize() > 0 ) + instance.setCloneSmellType(columbus::genealogy::cstMoving); + else + instance.setCloneSmellType(columbus::genealogy::cstNone); + } + } + } + } + + graphsupport::addNodeNameAttribute(graph, cloneInstanceGraphNode, instance.getUniqueName()); + graphsupport::setStringAttribute(graph, cloneInstanceGraphNode, graphsupport::graphconstants::ATTR_DCF_CLONESMELLTYPE, genealogy::Common::toString(instance.getCloneSmellType())); + + } + } + + // build virtual clone class + if (currentSystem->getPrev()) + { + columbus::genealogy::System& pervSystemRef = *currentSystem->getPrev(); + + for (auto groupIter = pervSystemRef.getCloneClassesListIteratorBegin(); groupIter != pervSystemRef.getCloneClassesListIteratorEnd(); ++groupIter) + { + columbus::genealogy::CloneClass& classItem = const_cast(*groupIter); + if (classItem.getIsVirtual()) + continue; + + if (groupIter->getNextIsEmpty()) + { + columbus::genealogy::CloneClass* cloneClassVirtual = classItem.getFactory().createCloneClassNode(); + currentSystem->addCloneClasses(cloneClassVirtual); + cloneClassVirtual->setUniqueNameKey(classItem.getUniqueNameKey()); + cloneClassVirtual->setIsVirtual(true); + cloneClassVirtual->setCloneSmellType(columbus::genealogy::cstDisappearing); + + auto cloneClassGraphNode = graph.createNode(getGraphNameOfGenelogyNode(*cloneClassVirtual), columbus::graph::Node::NodeType(graphsupport::graphconstants::NTYPE_DCF_CLONECLASS)); + graph.createDirectedEdge(graph.findNode(graphsupport::graphconstants::UID_CLONE_ROOT), cloneClassGraphNode, graphsupport::graphconstants::ETYPE_DCF_CLONETREE, true); + graphsupport::addNodeNameAttribute(graph, cloneClassGraphNode, cloneClassVirtual->getUniqueName()); + graphsupport::setStringAttribute(graph, cloneClassGraphNode, graphsupport::graphconstants::ATTR_DCF_CLONESMELLTYPE, genealogy::Common::toString(cloneClassVirtual->getCloneSmellType())); + + for(auto itemsIter = classItem.getItemsListIteratorBegin(); itemsIter != classItem.getItemsListIteratorEnd(); ++itemsIter) + { + columbus::genealogy::CloneInstance& cloneInstance= const_cast(*itemsIter); + + if (cloneInstance.getNextIsEmpty()) { + columbus::genealogy::CloneInstance* cloneInstanceNext = cloneInstance.getFactory().createCloneInstanceNode(); + cloneClassVirtual->addItems(cloneInstanceNext); + cloneInstanceNext->setCloneClass(&classItem); + cloneInstanceNext->setIsVirtual(true); + cloneInstanceNext->setUniqueNameKey(cloneInstance.getUniqueNameKey()); + cloneInstanceNext->setCloneSmellType(columbus::genealogy::cstNone); + cloneInstanceNext->addPrev(cloneInstance.getId()); + cloneInstanceNext->setPath(cloneInstance.getPath()); + cloneInstanceNext->setLine(cloneInstance.getLine()); + cloneInstanceNext->setEndLine(cloneInstance.getEndLine()); + cloneInstanceNext->setCol(cloneInstance.getCol()); + cloneInstanceNext->setEndCol(cloneInstance.getEndCol()); + + cloneInstance.addNext(cloneInstanceNext); + } + } + } + } + } + currentSystem->setFirstFreeID(uniqueId); + + updateMemoryStat(config); + common::WriteMsg::write(WriteMsg::mlDebug, "Debug: Generating unique names took %d (1/100s)\n", common::getProcessUsedTime().user - time.user); + } + + + void DuplicatedCodeMiner::createBackup(const std::string& backup) + { + + if ( !backup.empty() ) { + common::WriteMsg::write(CMSG_CREATE_BACKUP); + std::wstring backupW; + backupW.assign(backup.begin(),backup.end()); + boost::filesystem::path to_dir(backupW); + + if (!to_dir.is_complete()) { + to_dir = (boost::filesystem::current_path() / to_dir ); + } + + if (!boost::filesystem::exists(to_dir)) + boost::filesystem::create_directories(to_dir); + + for(columbus::genealogy::ListIterator cIter = currentSystem->getComponentsListIteratorBegin();cIter != currentSystem->getComponentsListIteratorEnd();++cIter) { + const columbus::genealogy::Base& component=*cIter; + columbus::genealogy::Component& cmp=(columbus::genealogy::Component&)component; + boost::filesystem::path p(cmp.getLocation()); + boost::filesystem::path newfile; + + if (p.is_complete()) + newfile=to_dir/p.relative_path(); + else + newfile=to_dir/(boost::filesystem::current_path()/p).relative_path(); + + + newfile.normalize(); + newfile.make_preferred(); + + newfile = LONGDIRPREFIXSTRING + newfile.wstring(); + + boost::filesystem::remove(newfile); + boost::filesystem::create_directories(boost::filesystem::path(newfile).remove_leaf()); + boost::filesystem::copy_file(p,newfile); + cmp.setLocation(newfile.string()); + p=boost::filesystem::change_extension(p, FILTER_FILE_EXTENSION_W); + newfile=boost::filesystem::change_extension(newfile, FILTER_FILE_EXTENSION_W); + boost::filesystem::remove(newfile); + if (boost::filesystem::exists(p)) + boost::filesystem::copy_file(p,newfile); + } + common::WriteMsg::write(CMSG_DONE_D); + } + } + + void DuplicatedCodeMiner::saveGenealogy() { + + if (!config.genealogyFilename.empty()){ + + if (config.smallGenealogy) { + // Remove the last system + if (lastSystem != NULL) { + genealogyFact->destroyNode(lastSystem->getId()); + } + } + + if ( dumpGraphml) + { + genealogy::AlgorithmPreorder pre; + pre.setFactory( *genealogyFact); + pre.setSafeMode(); + io::GraphmlIO ioToDumpGraphml((config.genealogyFilename+ ".graphml").c_str(), ""); + std::set tmpSet; + genealogy::VisitorGraphml visitorToDumpGraphml(ioToDumpGraphml, tmpSet); + pre.addVisitor(visitorToDumpGraphml); + pre.run(); + } + common::WriteMsg::write(CMSG_SAVE_GENEALOGY); + columbus::CsiHeader header; + genealogyFact->save(config.genealogyFilename, header); + common::WriteMsg::write(CMSG_DONE_D); + } + } + + bool DuplicatedCodeMiner::isASGNode(unsigned int sequencePosition) const { + return (serializationData.nodeInfoSequence.at(sequencePosition)!=NULL); + } + + const ASTNodeInfo* DuplicatedCodeMiner::getNode(unsigned int sequencePosition) const { + return serializationData.nodeInfoSequence.at(sequencePosition); + } + + bool DuplicatedCodeMiner::containsInstanceAtPositon(unsigned int position, const genealogy::CloneClass& cc) { + for(genealogy::ListIterator instances = cc.getItemsListIteratorBegin();instances != cc.getItemsListIteratorEnd();++instances) { + const genealogy::CloneInstance& ci = *instances; + if(positions[ci.getId()] == position) { + return true; + } + } + return false; + } + + std::string DuplicatedCodeMiner::computeCloneClassCode(unsigned int pos, unsigned int length) + { + std::string s("CLONE"); + + for (unsigned int i = 0; i < length; i++) + s.append(to_string(getNodeKindAt(pos + i))); + + auto hashCode = hash()(s); + return to_string(hashCode); + } + + void DuplicatedCodeMiner::alignCloneClass(Aligner::AlignKind alignKind, const SuffixArray::CloneClass& suffixCl, CloneClassPotentialCloneInstanceMap& potentialCloneInstances) + { + config.stat.numOfFoundsuffixInstances += suffixCl.num; + ++config.stat.numOfFoundsuffixClass; + unsigned int length = suffixCl.length; + int oneOccurance = suffixCl.position[0]; + const unsigned* instances = suffixCl.position; + + common::WriteMsg::write(CMSG_FUND_REPEATING_SEQ,oneOccurance,length+oneOccurance,suffixCl.num); + + // if (common::WriteMsg::getMessageLevel() >= common::WriteMsg::mlDDDebug ) { + // for (int i = 1;i offset; + std::list> intervals; + for (unsigned int i=0; i config.minAsgNodes || !config.singleAsgRoot) { + auto I = std::make_shared(lastOffset, i); + + list>::iterator iter=intervals.begin(); + while (iter != intervals.end()) + { + // removing contained intervals + auto current=(*iter); + if (*current <= *I) + iter=intervals.erase(iter); + else + break; + } + intervals.push_front(I); + } + offset.pop(); + } else { + // common::WriteMsg::write(CMSG_FUND_REPEATING_SEQ_6,oneOccurance+i); + //this node was not part of a whole syntax tree + //we cannot do anything at this point. + } + } + else + if (isASGNode(oneOccurance+i)) { + offset.push(i); + } + }//end for + + //at this point 'intervals' contains all the syntactic subtrees of the current clone class + //first we merge the available intervals + + if(!config.singleAsgRoot && !intervals.empty()) { + for(list>::iterator it1 = intervals.begin(), it2 = it1++; it1 != intervals.end() && it2 != intervals.end();) { + if((*it1)->b == (*it2)->a - 1 ) { + (*it1)->b = (*it2)->b; + if((*it2)->intervals == NULL) { + delete (*it1)->intervals; + (*it1)->intervals = new vector(); + } else { + (*it1)->intervals = (*it2)->intervals; + } + (*it1)->intervals->push_back((*it2)->a); + (*it2)->intervals = NULL; + intervals.erase(it2); + } + it2 = it1++; + } + } + + // create clone classes + + list>::iterator iter = intervals.begin(); + while (iter!=intervals.end()) { + auto I=*iter; + iter++; + unsigned intervalLength = I->b - I->a + 1; + if (intervalLength < config.minAsgNodes) { + common::WriteMsg::write(CMSG_FUND_REPEATING_SEQ_5,intervalLength); + continue; + } + + + bool isNew = true; + + genealogy::CloneClass* cc = createCloneClass(oneOccurance + I->a, intervalLength, isNew); + common::WriteMsg::write(CMSG_FUND_REPEATING_SEQ_3,cc->getId()); + for (unsigned posIt = 0; posIt < suffixCl.num; ++posIt) { + PotentialCloneInstance potI(instances[posIt], I); + //potI.dump(); + potentialCloneInstances[cc->getId()].insert(potI); + // common::WriteMsg::write(CMSG_FUND_REPEATING_SEQ_4,instances[posIt],instances[posIt]+I.a,instances[posIt]+I.b); + config.stat.numOfpotInstances++; + } + } + + }//end Syntax Boundary + + } + + genealogy::CloneClass* DuplicatedCodeMiner::createCloneClass(unsigned int position, unsigned int length, bool& isNewClass) { + + genealogy::CloneClass* cloneClass = NULL; + + //first we have to check if this clone class already exists + std::string code=computeCloneClassCode(position, length); + std::map::iterator iter=cloneClassMap.find(code); + + if (iter!=cloneClassMap.end()) { + isNewClass = false; + cloneClass = iter->second; + } else { + isNewClass = true; + cloneClass = genealogyFact->createCloneClassNode(); + + // The fingerprint is set only after the filtering stage as strings are not deleted from the stringtable when the nodes are deleted. + cloneClassFingerprintMap[cloneClass->getId()] = code; + cloneClass->setHeadNodeKind(getNodeKindAt(position)); + cloneClass->setType(genealogy::ctkType2); + lengths[cloneClass->getId()] = length; + currentSystem->addCloneClasses(cloneClass->getId()); + cloneClassMap.insert(make_pair(code, cloneClass)); + } + return cloneClass; + } + + const ASTNodeInfo* DuplicatedCodeMiner::getFirstNode(unsigned int from, unsigned int to) const { + for(unsigned int pos = from; pos <= to; ++pos) { + const ASTNodeInfo* nodePos = getNode(pos); + if(nodePos) + return nodePos; + } + return NULL; + } + + genealogy::CloneInstance* DuplicatedCodeMiner::createCloneInstance(unsigned int position, unsigned int length, unsigned int intervalStart, vector* intervals, genealogy::CloneClass& parent) + { + const ASTNodeInfo* firstNode = getFirstNode(position, position + length); + if (!firstNode) + throw Exception(COLUMBUS_LOCATION, CMSG_EX_UNABLE_TO_DETERMINE_THE_LINE_INFO); + + std::stack offset; + unsigned int lastOffset=0; + bool wasLastOffset=false; + + for(unsigned int i = 0; i < length; ++i) + { + int currentNodeKind = getNodeKindAt(position + i); + if( isDecDepthSign(currentNodeKind) ) + { + if(!offset.empty()) { + lastOffset = offset.top(); + wasLastOffset = true; + offset.pop(); + } else { + //this node was not part of a whole syntax tree + //we cannot do anything at this point. + } + } + else + if (isASGNode(position + i)) + { + offset.push(i); + } + } + if (!wasLastOffset) { + if (!offset.empty()) { + lastOffset=offset.top(); + } else + throw Exception(COLUMBUS_LOCATION, CMSG_EX_UNABLE_TO_DETERMINE_THE_LINE_INFO); + } + + const ASTNodeInfo* lastNode=getNode(position+lastOffset); + if (!lastNode) + throw Exception(COLUMBUS_LOCATION, CMSG_EX_UNABLE_TO_DETERMINE_THE_LINE_INFO); + + genealogy::CloneInstance& ci = *(genealogyFact->createCloneInstanceNode()); + ci.setLine(firstNode->getLine()); + ci.setCol(firstNode->getCol()); + ci.setEndLine(lastNode->getEndLine()); + ci.setEndCol(lastNode->getEndCol()); + + ci.setPath(firstNode->getStringPath().c_str()); + ci.setRootBegin(firstNode->getId()); + + + std::stringstream cloneInstanceRootNodes; + cloneInstanceRootNodes << std::hex; + cloneInstanceRootNodes << std::setw(8); + cloneInstanceRootNodes << std::setfill('0'); + cloneInstanceRootNodes << firstNode->getId(); + + //store into the ciIdToAST map + ciIdToAST[ci.getId()] = firstNode->getStringTUPath(); + + if(intervals ) { + ci.setRootLength(static_cast(intervals->size())+1); + + std::sort(intervals->begin(),intervals->end()); + + for (std::vector::iterator it = intervals->begin(); it != intervals->end(); ++it) { + const ASTNodeInfo* nodePos = getNode(intervalStart + *it); + if (nodePos) { + cloneInstanceRootNodes << std::hex; + cloneInstanceRootNodes << std::setw(8); + cloneInstanceRootNodes << std::setfill('0'); + cloneInstanceRootNodes << nodePos->getId(); + } + } + } else { + ci.setRootLength(1); + } + + // The root nodes is set only after the filtering stage as strings are not deleted from the stringtable when the nodes are deleted. + cloneInstanceRootNodesMap[ci.getId()] = cloneInstanceRootNodes.str(); + + positions[ci.getId()] = position; + + // set component + + + std::string componentNameInTheLimAsg = getComponentName( firstNode->getLimComponentId(),*limFact); + for (columbus::genealogy::ListIterator componentIt = currentSystem->getComponentsListIteratorBegin();componentIt != currentSystem->getComponentsListIteratorEnd();++componentIt) + { + const columbus::genealogy::Component& genealogyComponentNode = *componentIt; + if (genealogyComponentNode.getName() == componentNameInTheLimAsg) + { + ci.setComponent(genealogyComponentNode.getId()); + break; + } + } + + parent.setInstances(parent.getInstances()+1); + parent.addItems(ci.getId()); + ci.setCloneClass(&parent); + + common::WriteMsg::write(CMSG_CLONE_INSTANCE, ci.getId()); + //assign clone instance to the lim nodes + NodeId lastLimNodeID = 0; + + for (unsigned int i = 0; i < length;i++){ + const ASTNodeInfo* nodePos = getNode(position+i); + + if(nodePos) { + if ((nodePos->getLimNodeId() != 0) && + (lastLimNodeID != nodePos->getLimNodeId()) && + (!columbus::lim::asg::Common::getIsPackage(limFact->getRef(nodePos->getLimNodeId())))) + { + limNodeCloneInstanceMap[ci.getId()].insert(nodePos->getLimNodeId()); + limComponentCloneInstanceMap[ci.getId()].insert(nodePos->getLimComponentId()); + lastLimNodeID = nodePos->getLimNodeId(); + } + } + } + + updateMemoryStat(config); + return &ci; + } + + int DuplicatedCodeMiner::getNodeKindAt(unsigned int position) const { + return serializationData.nodeKindSequence.at(position); + } + + bool DuplicatedCodeMiner::getIsNeeded(const string& id) const { + if (config.metrics) + return rulHandler->getIsEnabled(id); + else + return false; + } + + bool DuplicatedCodeMiner::isDecDepthSign(int value) const { + return theCloneVisitor->isSepDecDepthSign(value); + } + + void DuplicatedCodeMiner::addValue(const string& warningType, const std::list& relType, const columbus::graph::Node& node, int value, bool sumUp) { + columbus::graphsupport::incMetricInt(graph, node.getUID(), warningType, value ); + if (sumUp) { + std::list nodes; + getParent(node, relType, nodes); + for(std::list::iterator it = nodes.begin(); it != nodes.end(); it++) { + addValue(warningType, relType, *it, value, true); + } + } + } + + columbus::graph::Node DuplicatedCodeMiner::findNodeByRange(columbus::graph::Graph& graph, const string& path, int line, int col, int endLine, int endCol) { + // remove \\\\ from lines + std::list nodes; + indexer->findNodesByRange(graph, path, line, col, endLine, endCol, nodes); + if(nodes.size() > 0) { + int min_line = INT_MIN, min_col = INT_MIN, min_endline = INT_MAX, min_endcol = INT_MAX; + std::string min_path = ""; + columbus::graph::Node minimalNode;/* = nodes.front();*/ + /*columbus::graphsupport::getPositionAttribute(minimalNode, min_path, min_line, min_col, min_endline, min_endcol);*/ + + for(std::list::iterator it = nodes.begin(); it != nodes.end(); it++) { + if(it->getType().getType() == graphsupport::graphconstants::NTYPE_DCF_CLONECLASS || it->getType().getType() == graphsupport::graphconstants::NTYPE_DCF_CLONEINSTANCE) + continue; + int act_line = 0, act_col = 0, act_endline = 0, act_endcol = 0; + std::string act_path = ""; + columbus::graphsupport::getPositionAttribute(*it, act_path, act_line, act_col, act_endline, act_endcol); + // if the clone not in the actual element we go the next iteration + if (act_line > line || act_endline < endLine) + continue; + if ((act_line > min_line || (act_line == min_line && act_col > min_col)) && + (act_endline < min_endline || (act_endline == min_endline && act_endcol < min_endcol)) + ) { + minimalNode = *it; + min_path = act_path; + min_line = act_line; + min_col = act_col; + min_endline = act_endline; + min_endcol = act_endcol; + } + } + return minimalNode; + } + return columbus::graph::Graph::invalidNode; + } + + void DuplicatedCodeMiner::getParent(const columbus::graph::Node& node, const std::list& relType, std::list& nodes) { + for (std::list::const_iterator itRelType = relType.begin();itRelType != relType.end();++itRelType) { + static map > parents; + map::iterator node_parent_it = parents[*itRelType].find(node); + if(node_parent_it != parents[*itRelType].end()) { + nodes.push_back(node_parent_it->second); + continue; + } + + unsigned parentCounter = 0; + columbus::graph::Node parent = columbus::graph::Graph::invalidNode; + // find parent node + columbus::graph::Edge::EdgeIterator edgeIt = node.findOutEdges( *itRelType); + while(edgeIt.hasNext()) { + ++parentCounter; + parent = edgeIt.next().getToNode(); + if( !(parent == columbus::graph::Graph::invalidNode)) + nodes.push_back(parent); + } + + if(parentCounter == 1) { + parents[*itRelType].insert(make_pair(node, nodes.back())); + } + + } + } + + DuplicatedCodeMiner::~DuplicatedCodeMiner() { + for (unsigned q=0; q cloneInstanceIt = cc.getItemsListIteratorBegin();cloneInstanceIt != cc.getItemsListIteratorEnd(); ++cloneInstanceIt) { + const genealogy::CloneInstance& ci = dynamic_cast(*cloneInstanceIt); + unsigned int instanceLength = (ci.getEndLine() - ci.getLine() + 1); + if(length > instanceLength) { + length = instanceLength; + } + } + if(length == INT_MAX) + length = 0; + const_cast(cc).setLength(length); + return length; + } + + void dumpCloneSmellType(const genealogy::Clone& clone, std::ostream& out) { + switch (clone.getCloneSmellType()) { + case genealogy::cstAppearing: + out << " Appeared"; + break; + case genealogy::cstMoving: + out << " Moved from " << (dynamic_cast(*clone.getPrevListIteratorBegin())).getCloneClass()->getUniqueName(); + break; + case genealogy::cstDisappearing: + out << " Disappeared"; + break; + case genealogy::cstNone: + default: + break; + } + } + + void dump(const genealogy::CloneInstance& ci, std::ostream& out) { + out << ci.getPath() <<"(" << ci.getLine() << "): " << ci.getUniqueName() << " [Ln:" << ci.getLine() << ", Col:" << ci.getCol() << " - Ln:"<< ci.getEndLine() <<", Col:"<< ci.getEndCol() <<"]"; + dumpCloneSmellType(ci, out); + out << "\n"; + } + + + + void dump(const genealogy::CloneClass& cc, std::ostream& out) { + //dump clone instance + out << cc.getUniqueName() << " [Number of Clone Instances: " << DuplicatedCodeMiner::getRealNumberCi(cc) << ", Lines of Code: " << DuplicatedCodeMiner::getLength(cc) << "]"; + dumpCloneSmellType(cc, out); + out << "\n"; + + // The current instances + for(genealogy::ListIterator cloneInstanceIt = cc.getItemsListIteratorBegin(); cloneInstanceIt != cc.getItemsListIteratorEnd();++cloneInstanceIt) { + const genealogy::CloneInstance& ci = dynamic_cast(*cloneInstanceIt); + dump(ci, out); + } + out << "\n"; + } + + void DuplicatedCodeMiner::dumpLastSystem(std::ostream& out) { + + out << "Number of Clone Classes: " << getRealNumberCC( *currentSystem) << std::endl << std::endl; + + // The current classes + for(genealogy::ListIterator cloneClassIt = currentSystem->getCloneClassesListIteratorBegin();cloneClassIt != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIt) { + const genealogy::CloneClass& cc = dynamic_cast(*cloneClassIt); + dump(cc, out); + } + } + + int DuplicatedCodeMiner::getCloneClassNum() const { + return currentSystem->getCloneClassesSize() ; + } + + void DuplicatedCodeMiner::exportGraph(const std::string& filename) { + if(config.exportRul) + graphsupport::buildRulToGraph(graph, *rulHandler); + graph.saveBinary(filename); + } + + unsigned int DuplicatedCodeMiner::getPosition(NodeId id) const{ + std::map::const_iterator pos = positions.find(id); + if(pos != positions.end()) { + return pos->second; + } else { + return 0; + } + } + + unsigned int DuplicatedCodeMiner::getLength(NodeId id) const{ + std::map::const_iterator len = lengths.find(id); + if(len != lengths.end()) { + return len->second; + } else { + return 0; + } + } + + bool DuplicatedCodeMiner::initLim() + { + common::WriteMsg::write(CMSG_INITIALIZING_LIM); + strTable = new RefDistributorStrTable(); + + if (limFact != NULL) + delete limFact; + + if (!config.limFileName.empty()) { + boost::filesystem::path limFilePath(config.limFileName); + if (boost::filesystem::exists(limFilePath)) { + try { + limFact = new columbus::lim::asg::Factory(*strTable, "", columbus::lim::asg::limLangOther); + std::list headerList; + headerList.push_back(&limOrigin); + limFact->load(config.limFileName, headerList); + limFact->initializeFilter(); + + boost::filesystem::path f(config.limFileName); + try { + f=boost::filesystem::change_extension(f, LIM_FILTER_FILE_EXTENSION); + if (common::fileTimeCmp(f.string(), config.limFileName) == -1) { + common::WriteMsg::write(CMSG_FILTER_FILE_OLD, f.string().c_str()); + } else { + if(common::pathFileExists(f.string().c_str(), false)) + { + limFact->loadFilter(f.string()); + } + } + } catch (columbus::Exception& e) { + common::WriteMsg::write(CMSG_FILTER_FILE_CANNOT_BE_LOADED , f.string().c_str()); + common::WriteMsg::write(CMSG_CAUSE, e.getMessage().c_str()); + } + + } + catch (columbus::lim::asg::LimException& e) { + common::WriteMsg::write(CMSG_FAILED); + common::WriteMsg::write(CMSG_SIMPLE_STRING_TRANSMIT_ERR, e.getMessage().c_str() ); + return false; + } + } else { + common::WriteMsg::write(CMSG_FAILED); + return false; + } + } else { + common::WriteMsg::write(CMSG_FAILED); + return false; + } + + class FileSystemVisitor :public columbus::lim::asg::Visitor + { + public: + int maxNDC; + + FileSystemVisitor() + :maxNDC(0) + {} + + std::list files; + + struct NdcDepthPair { + NdcDepthPair(int depth, int subMaxNDC) :depth(depth), subMaxNDC(subMaxNDC) {} + int depth; + int subMaxNDC; + }; + + NdcDepthPair calculateMaxDistance(columbus::lim::asg::physical::Folder& node) { + string s = lim::asg::Common::getFullPath(node); + + if (node.getContainsIsEmpty()) { + return NdcDepthPair(1,0); + } + + if (node.getContainsSize() == 1) { + if (lim::asg::Common::getIsFile(* node.getContainsListIteratorBegin())) { + return NdcDepthPair(2,0); + } else { + NdcDepthPair subtreeValues = calculateMaxDistance((columbus::lim::asg::physical::Folder&)*node.getContainsListIteratorBegin()); + subtreeValues.depth++; + return subtreeValues; + } + } else { + int maxNDC =0; + int maxDept = 0; + int maxDepth2 = 0; + + for (columbus::lim::asg::ListIterator it = node.getContainsListIteratorBegin();it != node.getContainsListIteratorEnd();++it ) { + NdcDepthPair subtreeValues = NdcDepthPair(0,0); + + if (lim::asg::Common::getIsFile(* it)) { + subtreeValues = NdcDepthPair(1,0); + } else { + subtreeValues = calculateMaxDistance((columbus::lim::asg::physical::Folder&)*it); + } + if (subtreeValues.subMaxNDC > maxNDC) { + maxNDC = subtreeValues.subMaxNDC; + } + + if (subtreeValues.depth > maxDept) { + maxDepth2 = maxDept; + maxDept = subtreeValues.depth ; + } else if (subtreeValues.depth > maxDepth2) { + maxDepth2 = subtreeValues.depth ; + } + + } + + int ndc = maxDept+maxDepth2; + if (ndc < maxNDC) { + ndc = maxNDC; + } + return NdcDepthPair(maxDept+1,ndc); + } + return NdcDepthPair(1,0); + } + + + void visit(const columbus::lim::asg::physical::FileSystem& node , bool callVirtualBase) { + int maxDept = 0; + int maxDept2 = 0; + for (columbus::lim::asg::ListIterator it = node.getFSEntryListIteratorBegin();it != node.getFSEntryListIteratorEnd();++it ) { + if (lim::asg::Common::getIsFolder(* it)) { + NdcDepthPair result = calculateMaxDistance((columbus::lim::asg::physical::Folder&) (*it)); + + if (maxNDC < (result.subMaxNDC)){ + maxNDC = (result.subMaxNDC); + } + if (maxDept < result.depth) { + if (maxDept2 < maxDept ) { + maxDept2 = maxDept; + } + maxDept = result.depth; + } else { + if (maxDept2 < result.depth ) { + maxDept2 = result.depth; + } + } + } + } + + + if (maxDept && maxDept2 && (maxNDC < maxDept+maxDept2)) { + maxNDC = maxDept2+maxDept; + } + + } + + }; + + FileSystemVisitor fileSystemVisitor; + columbus::lim::asg::AlgorithmPreorder ap ; + + + if (getIsNeeded("NCR")) { + ap.run(*limFact,fileSystemVisitor); + } + + currentSystemMaxNDC = (fileSystemVisitor.maxNDC> 0 ? (fileSystemVisitor.maxNDC-1) :0) +1; + + set componenetsInLim; + + //check components + for (lim::asg::Factory::const_iterator it = limFact->begin();it != limFact->end();++it) { + if (lim::asg::Common::getIsComponent(**it)){ + const std::string& name = dynamic_cast(*it)->getName(); + componenetsInLim.insert(name ); + } + } + + bool componetOK = true; + + limFact->turnFilterOff(); + return componetOK; + } + + void DuplicatedCodeMiner::setFilterOut(ostream& out) { + filterOut = &out; + } + + void clearNodeIdSequence(std::vector& nodeInfoSequence) { + for (size_t q=0; q& relType, std::set& nodesList ) { + std::list nodes; + getParent(node, relType, nodes); + for(std::list::iterator it = nodes.begin(); it != nodes.end(); it++) { + getParentTransitve(*it,relType,nodesList); + nodesList.insert(*it); + } + } + + std::string DuplicatedCodeMiner::getGraphNameOfGenelogyNode( const columbus::genealogy::Base& genealogyBase ) { + std::string s("C"); + return s + boost::lexical_cast(genealogyBase.getId()); + } + + NodeId DuplicatedCodeMiner::getLimComponenetIdByName( const std::string& name, const columbus::lim::asg::Factory& factory ) { + vector components; + for ( columbus::lim::asg::Factory::const_iterator it = factory.begin();it != factory.end();++it) { + if (lim::asg::Common::getIsComponent(**it) ) { + const string& compname = static_cast< const columbus::lim::asg::base::Component*>(*it)->getName(); + if (! (compname.compare(name) ) ) { + return (*it)->getId(); + } + components.push_back(static_cast< const columbus::lim::asg::base::Component*>(*it)); + } + } + + for (auto componentNode : components) + { + if (componentNode->getName().find(name) != string::npos) + { + common::WriteMsg::write(CMSG_FILENAME_COMPONENT_MATCH, name.c_str()); + return componentNode->getId(); + } + } + + return 0; + } + + const std::string& DuplicatedCodeMiner::getComponentName( columbus::NodeId limId, const columbus::lim::asg::Factory& factory ) const + { + const std::string& refEmptyString = limFact->getStringTable().get(limFact->getStringTable().set("")); + + if (limId == 0) + return refEmptyString; + + if (!factory.getExist(limId)) + return refEmptyString; + + if (lim::asg::Common::getIsComponent(factory.getRef(limId))) + { + lim::asg::base::Component& refComp = static_cast (factory.getRef(limId)); + return refComp.getName(); + } + return refEmptyString; + } + + const ASTNodeInfo* DuplicatedCodeMiner::getEndNode( unsigned int from, unsigned int to ) const + { + for(unsigned int pos = to; pos >= from; --pos) { + const ASTNodeInfo* nodePos = getNode(pos); + if(nodePos) + return nodePos; + } + return NULL; + } + + int DuplicatedCodeMiner::getCloneInstanceNum() const { + int ret = 0; + for(genealogy::ListIterator cloneClassIt = currentSystem->getCloneClassesListIteratorBegin();cloneClassIt != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIt) { + const genealogy::CloneClass& cc = dynamic_cast(*cloneClassIt); + ret += cc.getItemsSize(); + } + return ret; + } + + unsigned int DuplicatedCodeMiner::getRealNumberCi( const genealogy::CloneClass& cc ) { + unsigned int ret= 0; + for (columbus::genealogy::ListIterator itemsIter=cc.getItemsListIteratorBegin();itemsIter!=cc.getItemsListIteratorEnd();++itemsIter) { + if (!itemsIter->getIsVirtual()) { + ret++; + } + } + return ret; + } + + unsigned int DuplicatedCodeMiner::getRealNumberCC( const genealogy::System& sys ) + { + unsigned int ret= 0; + for (columbus::genealogy::ListIterator itemsIter=sys.getCloneClassesListIteratorBegin();itemsIter!=sys.getCloneClassesListIteratorEnd();++itemsIter) { + if (!itemsIter->getIsVirtual() ) { + ret++; + } + } + return ret; + } + + void DuplicatedCodeMiner::addParentComponents( std::set &componentsOfTheClass, NodeId currentComp ) + { + componentsOfTheClass.insert(currentComp); + for ( columbus::lim::asg::ListIterator + it = limFact->getReverseEdges().constIteratorBegin(currentComp,columbus::lim::asg::edkComponent_Contains); + it != limFact->getReverseEdges().constIteratorEnd(currentComp,columbus::lim::asg::edkComponent_Contains); + ++it) { + addParentComponents(componentsOfTheClass,it->getId()); + } + } + + void DuplicatedCodeMiner::collectContainerFiles( const lim::asg::logical::Package &package, std::set &fileNames ) + { + + for ( lim::asg::ListIteratorAssocSourcePosition it = package.getIsContainedInListIteratorAssocBegin(); + it != package.getIsContainedInListIteratorAssocEnd();++it) { + std::string path = lim::asg::Common::getFullPath(*it); + LowerStringOnWindows(path); + fileNames.insert( limFact->getStringTable().set( path ) ); + } + + for (lim::asg::ListIterator it = package.getMemberListIteratorBegin(); it != package.getMemberListIteratorEnd() ;++it) { + if (lim::asg::Common::getIsPackage(*it)) { + const lim::asg::logical::Package& subPackage = (const lim::asg::logical::Package&) *it; + collectContainerFiles(subPackage,fileNames); + } + } + } + + columbus::Key DuplicatedCodeMiner::getUniformPathKey( Key key, StrTable& strtable ) + { + std::string origStr = strtable.get(key); + std::replace(origStr.begin(),origStr.end(),'\\','/'); + return strtable.set(origStr); + } + + void DuplicatedCodeMiner::setStatementFilter( bool val ) + { + statementFilter = val; + } + + + int DuplicatedCodeMiner::getLimNodeDepth(NodeId nodeId) + { + auto searchResult = nodeDepthCache.getValue(nodeId); + if (searchResult.found) + return searchResult.value; + + NodeId parent = getLimNodeParent(nodeId); + int depth = 0; + if (parent != 0) + depth = getLimNodeDepth(parent) + 1; + + nodeDepthCache.setValue(nodeId, depth); + return depth; + } + + /** + Calculates the CCO - McCabe complexity + */ + void DuplicatedCodeMiner::calculateCCO() + { + + auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("calculateCCO()"); + common::timestat time = common::getProcessUsedTime(); + + for (auto cloneClassIter = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIter != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIter) + { + int ClassCCO = 0; + auto length = lengths[cloneClassIter->getId()]; + for (auto cloneInstanceIter = cloneClassIter->getItemsListIteratorBegin(); cloneInstanceIter != cloneClassIter->getItemsListIteratorEnd(); ++cloneInstanceIter) + { + int CCO = 1; + auto startPosition = positions[cloneInstanceIter->getId()]; + + for (size_t index = startPosition; index < startPosition + length; ++index) + { + const auto nodeInfo = serializationData.nodeInfoSequence[index]; + const int nodeKind = serializationData.nodeKindSequence[index]; + if (nodeInfo != nullptr) + { + if ((nodeKind & NodeMask::NodeTypeMask) == NodeType::Statement) + { + switch (nodeKind & NodeMask::NodeKindMask) + { + case clang::Stmt::IfStmtClass: + case clang::Stmt::ForStmtClass: + case clang::Stmt::CXXForRangeStmtClass: + case clang::Stmt::WhileStmtClass: + case clang::Stmt::DoStmtClass: + case clang::Stmt::CaseStmtClass: + case clang::Stmt::CXXCatchStmtClass: + case clang::Stmt::ObjCAtCatchStmtClass: + case clang::Stmt::ConditionalOperatorClass: + case clang::Stmt::BinaryConditionalOperatorClass: + ++CCO; + break; + + case clang::Stmt::BinaryOperatorClass: + if ((nodeKind & NodeMask::LogicalBOMask) == NodeBOType::LogicalBinaryOperator) + ++CCO; + break; + } + + } + + } + } + + graphsupport::setMetricInt(graph, + getGraphNameOfGenelogyNode(*cloneInstanceIter), + "CCO", + CCO); + // At the moment there is only constant reference operator for the + // ListIterator class and it is faster to const_cast it than getting + // a non const referenc from the factory by its ID. + const_cast(*cloneInstanceIter).setCco(CCO); + + ClassCCO += CCO; + } + + graphsupport::setMetricInt(graph, + getGraphNameOfGenelogyNode(*cloneClassIter), + "CCO", + ClassCCO); + + + // At the moment there is only constant reference operator for the + // ListIterator class and it is faster to const_cast it than getting + // a non const referenc from the factory by its ID. + const_cast(*cloneClassIter).setCco(ClassCCO); + + } + + // This part is almost perfect clone of the CI metric calculation !!!!!!!! + // It collects the clone instances for each source code elments + + map> sourceCodeElementLimId2CloneInstanceGenelogyIdMap; + + // Calculate the number of clone instances for each source code element + for (auto cloneClassIter = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIter != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIter) + { + for (auto cloneInstanceIter = cloneClassIter->getItemsListIteratorBegin(); cloneInstanceIter != cloneClassIter->getItemsListIteratorEnd(); ++cloneInstanceIter) + { + const auto& correspondingSourceCodeElements = limNodeCloneInstanceMap[cloneInstanceIter->getId()]; + for (auto limNodeId : correspondingSourceCodeElements) + sourceCodeElementLimId2CloneInstanceGenelogyIdMap[limNodeId].insert(cloneInstanceIter->getId()); + } + } + + // Copy the nodeids of the related LIM nodes into a separate container with their depth to prepare them for aggregation + set> cloneRelatedLimNodes; + + for (const auto& sourceCodeElementClones : sourceCodeElementLimId2CloneInstanceGenelogyIdMap) + cloneRelatedLimNodes.insert({ -getLimNodeDepth(sourceCodeElementClones.first), sourceCodeElementClones.first }); + + // Add the corresponding component nodes too + for (const auto& cloneRelatedLimNodeInfo : cloneRelatedLimNodes) + { + NodeId currentLimNodeId = cloneRelatedLimNodeInfo.second; + auto& currentLimNode = static_cast(limFact->getRef(currentLimNodeId)); + for (auto componentIt = currentLimNode.getBelongsToListIteratorBegin(); componentIt != currentLimNode.getBelongsToListIteratorEnd(); ++componentIt) + { + const NodeId componentId = componentIt->getId(); + // Add the clone instances to the component node + sourceCodeElementLimId2CloneInstanceGenelogyIdMap[componentId].insert(sourceCodeElementLimId2CloneInstanceGenelogyIdMap[currentLimNodeId].begin(), + sourceCodeElementLimId2CloneInstanceGenelogyIdMap[currentLimNodeId].end()); + // Add the component nodes with a positive depth to be sure that they will be processed after all other nodes + // Since the component tree is flat (all but the system component is on level 1. + cloneRelatedLimNodes.insert({1 , componentId}); + } + } + + updateMemoryStat(config); + + // Aggregate counters to the parents + while (!cloneRelatedLimNodes.empty()) + { + auto cloneRelatedLimNodesIt = cloneRelatedLimNodes.begin(); + int currentDepth = cloneRelatedLimNodesIt->first; + NodeId currentLimNodeId = cloneRelatedLimNodesIt->second; + auto cloneInstancesOfTheCurrentNode = sourceCodeElementLimId2CloneInstanceGenelogyIdMap[currentLimNodeId]; + NodeId parentNodeId = getLimNodeParent(currentLimNodeId); + +/* // Debug + printf("LimId:%d (%d) : %lu\n", currentLimNodeId, currentDepth, cloneInstancesOfTheCurrentNode.size()); +*/ + + if (parentNodeId != 0) + { + // Add instances to the parent + sourceCodeElementLimId2CloneInstanceGenelogyIdMap[parentNodeId].insert(cloneInstancesOfTheCurrentNode.begin(), + cloneInstancesOfTheCurrentNode.end()); + + // add the parent to the set + cloneRelatedLimNodes.insert({currentDepth + 1, parentNodeId }); + } + + // Set the CCO metric for LIM element + int CCOSum = 0; + for (auto cloneInstanceID : cloneInstancesOfTheCurrentNode) + CCOSum += ((genealogy::CloneInstance&)genealogyFact->getRef(cloneInstanceID)).getCco(); + + graphsupport::setMetricInt(graph, + lim2graph::VisitorGraphConverter::determineNodeName(currentLimNodeId), + "CCO", + CCOSum); + + + // remove the current node from the set + cloneRelatedLimNodes.erase(cloneRelatedLimNodesIt); + } + + + //--------------------------------------------------------------------------------// + updateMemoryStat(config); + common::WriteMsg::write(WriteMsg::mlDebug, "Debug: Computing CCO took %d (1/100s)\n", common::getProcessUsedTime().user - time.user); + } + + void DuplicatedCodeMiner::calculateCCL() + { + auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("calculateCCL()"); + common::timestat time = common::getProcessUsedTime(); + + // Map to store the the related clone classes for each source code element; + map> sourceCodeElementLimId2CloneClassGenalogyIdMap; + + // Collect the related clone classes for each related sourcecode elements + for (auto cloneClassIter = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIter != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIter) + { + for (auto cloneInstanceIter = cloneClassIter->getItemsListIteratorBegin(); cloneInstanceIter != cloneClassIter->getItemsListIteratorEnd(); ++cloneInstanceIter) + { + const auto& correspondingSourceCodeElements = limNodeCloneInstanceMap[cloneInstanceIter->getId()]; + for (auto limNodeId : correspondingSourceCodeElements) + sourceCodeElementLimId2CloneClassGenalogyIdMap[limNodeId].insert(cloneClassIter->getId()); + } + } + + +/* // Debug + for (const auto& sourceCodeElementClones : sourceCodeElementLimId2CloneClassGenalogyIdMap) + { + const auto& limNode = dynamic_cast(limFact->getRef(sourceCodeElementClones.first)); + printf("%d (%s,\t%s)\n", sourceCodeElementClones.first, columbus::lim::asg::Common::toString(limNode.getNodeKind()).c_str(), limNode.getName().c_str()); + + for (auto cloneClassId : sourceCodeElementClones.second) + { + printf("%d ", cloneClassId); + } + printf("\n"); + } +*/ + // Copy the nodeids of the related LIM nodes into a separate container with their depth to prepare them for aggregation + set> cloneRelatedLimNodes; + + for (const auto& sourceCodeElementClones : sourceCodeElementLimId2CloneClassGenalogyIdMap) + cloneRelatedLimNodes.insert({ -getLimNodeDepth(sourceCodeElementClones.first), sourceCodeElementClones.first }); + + // Add the corresponding component nodes too + for (const auto& cloneRelatedLimNodeInfo : cloneRelatedLimNodes) + { + NodeId currentLimNodeId = cloneRelatedLimNodeInfo.second; + auto& currentLimNode = static_cast(limFact->getRef(currentLimNodeId)); + for (auto componentIt = currentLimNode.getBelongsToListIteratorBegin(); componentIt != currentLimNode.getBelongsToListIteratorEnd(); ++componentIt) + { + const NodeId componentId = componentIt->getId(); + // Add the clone classes to the component nodes + sourceCodeElementLimId2CloneClassGenalogyIdMap[componentId].insert(sourceCodeElementLimId2CloneClassGenalogyIdMap[currentLimNodeId].begin(), + sourceCodeElementLimId2CloneClassGenalogyIdMap[currentLimNodeId].end()); + + // Add the component nodes with a positive depth to be sure that they will be processed after all other nodes + // Since the component tree is flat (all but the system component is on level 1. + cloneRelatedLimNodes.insert({1 , componentId}); + } + } + +/* // Debug + printf("----------\n"); + for (const auto& x : cloneRelatedLimNodes) + { + printf("x:%d -> %d\n", x.first, x.second); + } + printf("----------\n"); +*/ + + updateMemoryStat(config); + + // After collecting them we should aggregate the sets up on the parents to be able to set the CCL metric by the number of elements in the sets + // The ordering of the aggregation is very importat! Whe should start it with the furthest node so we use negative distances to be able to + // use the default comparison of the std::pair. (All the components starts with depth 1) + while (!cloneRelatedLimNodes.empty()) + { + auto cloneRelatedLimNodesIt = cloneRelatedLimNodes.begin(); + int currentDepth = cloneRelatedLimNodesIt->first; + NodeId currentLimNodeId = cloneRelatedLimNodesIt->second; + auto cloneClassesOfTheCurrrentNode = sourceCodeElementLimId2CloneClassGenalogyIdMap[currentLimNodeId]; + NodeId parentNodeId = getLimNodeParent(currentLimNodeId); + +/* // Debug + printf("LimId:%d (%d)\n", currentLimNodeId, currentDepth); +*/ + if (parentNodeId != 0) + { + // copy the related clone classes to the parent node + sourceCodeElementLimId2CloneClassGenalogyIdMap[parentNodeId].insert(cloneClassesOfTheCurrrentNode.begin(), + cloneClassesOfTheCurrrentNode.end()); + // add the parent to the set + cloneRelatedLimNodes.insert({currentDepth + 1, parentNodeId }); + } + + // set the CCL metric of the current source code element + graphsupport::setMetricInt(graph, + lim2graph::VisitorGraphConverter::determineNodeName(currentLimNodeId), + "CCL", + cloneClassesOfTheCurrrentNode.size()); + + // remove the current node from the set + cloneRelatedLimNodes.erase(cloneRelatedLimNodesIt); + } + +/* // Debug + printf("--------------------------------------\n"); + for (const auto& sourceCodeElementClones : sourceCodeElementLimId2CloneClassGenalogyIdMap) + { + const auto& limNode = dynamic_cast(limFact->getRef(sourceCodeElementClones.first)); + printf("%d (%s,\t%s)\n", sourceCodeElementClones.first, columbus::lim::asg::Common::toString(limNode.getNodeKind()).c_str(), limNode.getName().c_str()); + + for (auto cloneClassId : sourceCodeElementClones.second) + { + printf("%d ", cloneClassId); + } + printf("\n"); + } +*/ + updateMemoryStat(config); + + common::WriteMsg::write(WriteMsg::mlDebug, "Debug: Computing CCL took %d (1/100s)\n", common::getProcessUsedTime().user - time.user); + } + + void DuplicatedCodeMiner::calculateCC() + { + auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("calculateCC()"); + common::timestat time = common::getProcessUsedTime(); + + + // Calculate the number of nodes by the serialized AST for each LIM node + map nodeCountMap; + for (const auto nodeInfo : serializationData.nodeInfoSequence) + { + if (nodeInfo != nullptr) + { + NodeId limNodeId = nodeInfo->getLimNodeId(); + if (limNodeId != 0) + { + ++nodeCountMap[limNodeId]; + + auto& currentLimNode = static_cast(limFact->getRef(limNodeId)); + for (auto componentIt = currentLimNode.getBelongsToListIteratorBegin(); componentIt != currentLimNode.getBelongsToListIteratorEnd(); ++componentIt) + ++nodeCountMap[componentIt->getId()]; + } + } + } + + // Calculate the clone covered nodes of serialized AST for each LIM node + map> coveredNodeCountMap; + for (auto cloneClassIter = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIter != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIter) + { + auto length = lengths[cloneClassIter->getId()]; + for (auto cloneInstanceIter = cloneClassIter->getItemsListIteratorBegin(); cloneInstanceIter != cloneClassIter->getItemsListIteratorEnd(); ++cloneInstanceIter) + { + auto startPosition = positions[cloneInstanceIter->getId()]; + for (size_t index = startPosition; index < startPosition + length; ++index) + { + const auto nodeInfo = serializationData.nodeInfoSequence[index]; + if (nodeInfo != nullptr) + { + NodeId limNodeId = nodeInfo->getLimNodeId(); + if (limNodeId != 0) + coveredNodeCountMap[limNodeId].insert(index); + + } + } + } + } + +/* // Debug + for (auto coveredNodeCountMapElement : coveredNodeCountMap) + printf("Lim:%d Count:%lu Covered:%lu\n", coveredNodeCountMapElement.first, nodeCountMap[coveredNodeCountMapElement.first], coveredNodeCountMapElement.second.size()); +*/ + // Aggregate the counters to the parents + + // set to store all the source code elements which has a clone instance + set< /* LIM */ NodeId> relatedSourceCodeElementLimId; + + // Collect the LIM nodeids of the affected source code elements + for (auto cloneClassIter = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIter != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIter) + { + for (auto cloneInstanceIter = cloneClassIter->getItemsListIteratorBegin(); cloneInstanceIter != cloneClassIter->getItemsListIteratorEnd(); ++cloneInstanceIter) + { + const auto& correspondingSourceCodeElements = limNodeCloneInstanceMap[cloneInstanceIter->getId()]; + relatedSourceCodeElementLimId.insert(correspondingSourceCodeElements.begin(), correspondingSourceCodeElements.end()); + } + } + + + // Copy the nodeids of the related LIM nodes into a separate container with their depth to prepare them for aggregation + set> cloneRelatedLimNodes; + + for (auto limNodeId : relatedSourceCodeElementLimId) + cloneRelatedLimNodes.insert({ -getLimNodeDepth(limNodeId), limNodeId }); + + + // Add the corresponding component nodes too + // Since the component tree is flat (all but the system component is on level 1. + + for (const auto& cloneRelatedLimNodeInfo : cloneRelatedLimNodes) + { + NodeId currentLimNodeId = cloneRelatedLimNodeInfo.second; + auto& currentLimNode = static_cast(limFact->getRef(currentLimNodeId)); + for (auto componentIt = currentLimNode.getBelongsToListIteratorBegin(); componentIt != currentLimNode.getBelongsToListIteratorEnd(); ++componentIt) + { + const NodeId componentId = componentIt->getId(); + + coveredNodeCountMap[componentId].insert(coveredNodeCountMap[currentLimNodeId].begin(), coveredNodeCountMap[currentLimNodeId].end()); + + cloneRelatedLimNodes.insert({1 , componentId}); + } + } + + updateMemoryStat(config); + + // Aggregate counters to the parents + while (!cloneRelatedLimNodes.empty()) + { + auto cloneRelatedLimNodesIt = cloneRelatedLimNodes.begin(); + int currentDepth = cloneRelatedLimNodesIt->first; + NodeId currentLimNodeId = cloneRelatedLimNodesIt->second; + NodeId parentNodeId = getLimNodeParent(currentLimNodeId); + + + + auto currentNodeCountValue = nodeCountMap[currentLimNodeId]; + const auto& currentCoveredNodes = coveredNodeCountMap[currentLimNodeId]; + +/* // Debug + printf("LimId:%d (%d) : %lu %lu\n", currentLimNodeId, currentDepth, currentNodeCountValue, currentCoveredNodes.size()); +*/ + + if (parentNodeId != 0) + { + // Add the counters to the parent node + nodeCountMap[parentNodeId] += currentNodeCountValue; + coveredNodeCountMap[parentNodeId].insert(currentCoveredNodes.begin(), currentCoveredNodes.end()); + + // add the parent to the set + cloneRelatedLimNodes.insert({currentDepth + 1, parentNodeId }); + } + + // set the CC metric of the current source code element + graphsupport::setMetricFloat(graph, + lim2graph::VisitorGraphConverter::determineNodeName(currentLimNodeId), + "CC", + (double)currentCoveredNodes.size() / currentNodeCountValue); + + // remove the current node from the set + cloneRelatedLimNodes.erase(cloneRelatedLimNodesIt); + } + + updateMemoryStat(config); + common::WriteMsg::write(WriteMsg::mlDebug, "Debug: Computing CC took %d (1/100s)\n", common::getProcessUsedTime().user - time.user); + } + + + void DuplicatedCodeMiner::calculateCI() + { + auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("calculateCI()"); + common::timestat time = common::getProcessUsedTime(); + + map> sourceCodeElementLimId2CloneInstanceGenelogyIdMap; + + // Calculate the number of clone instances for each source code element + for (auto cloneClassIter = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIter != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIter) + { + for (auto cloneInstanceIter = cloneClassIter->getItemsListIteratorBegin(); cloneInstanceIter != cloneClassIter->getItemsListIteratorEnd(); ++cloneInstanceIter) + { + const auto& correspondingSourceCodeElements = limNodeCloneInstanceMap[cloneInstanceIter->getId()]; + for (auto limNodeId : correspondingSourceCodeElements) + sourceCodeElementLimId2CloneInstanceGenelogyIdMap[limNodeId].insert(cloneInstanceIter->getId()); + } + + // Set the CI metric for the clone classes + graphsupport::setMetricInt(graph, + getGraphNameOfGenelogyNode(*cloneClassIter), + "CI", + cloneClassIter->getInstances()); + } + + // Copy the nodeids of the related LIM nodes into a separate container with their depth to prepare them for aggregation + set> cloneRelatedLimNodes; + + for (const auto& sourceCodeElementClones : sourceCodeElementLimId2CloneInstanceGenelogyIdMap) + cloneRelatedLimNodes.insert({ -getLimNodeDepth(sourceCodeElementClones.first), sourceCodeElementClones.first }); + + // Add the corresponding component nodes too + for (const auto& cloneRelatedLimNodeInfo : cloneRelatedLimNodes) + { + NodeId currentLimNodeId = cloneRelatedLimNodeInfo.second; + auto& currentLimNode = static_cast(limFact->getRef(currentLimNodeId)); + for (auto componentIt = currentLimNode.getBelongsToListIteratorBegin(); componentIt != currentLimNode.getBelongsToListIteratorEnd(); ++componentIt) + { + const NodeId componentId = componentIt->getId(); + // Add the clone instances to the component node + sourceCodeElementLimId2CloneInstanceGenelogyIdMap[componentId].insert(sourceCodeElementLimId2CloneInstanceGenelogyIdMap[currentLimNodeId].begin(), + sourceCodeElementLimId2CloneInstanceGenelogyIdMap[currentLimNodeId].end()); + // Add the component nodes with a positive depth to be sure that they will be processed after all other nodes + // Since the component tree is flat (all but the system component is on level 1. + cloneRelatedLimNodes.insert({1 , componentId}); + } + } + + updateMemoryStat(config); + + // Aggregate counters to the parents + while (!cloneRelatedLimNodes.empty()) + { + auto cloneRelatedLimNodesIt = cloneRelatedLimNodes.begin(); + int currentDepth = cloneRelatedLimNodesIt->first; + NodeId currentLimNodeId = cloneRelatedLimNodesIt->second; + auto cloneInstancesOfTheCurrentNode = sourceCodeElementLimId2CloneInstanceGenelogyIdMap[currentLimNodeId]; + NodeId parentNodeId = getLimNodeParent(currentLimNodeId); + +/* // Debug + printf("LimId:%d (%d) : %lu\n", currentLimNodeId, currentDepth, cloneInstancesOfTheCurrentNode.size()); +*/ + + if (parentNodeId != 0) + { + // Add instances to the parent + sourceCodeElementLimId2CloneInstanceGenelogyIdMap[parentNodeId].insert(cloneInstancesOfTheCurrentNode.begin(), + cloneInstancesOfTheCurrentNode.end()); + + // add the parent to the set + cloneRelatedLimNodes.insert({currentDepth + 1, parentNodeId }); + } + + // Set the CI metric for LIM element + graphsupport::setMetricInt(graph, + lim2graph::VisitorGraphConverter::determineNodeName(currentLimNodeId), + "CI", + cloneInstancesOfTheCurrentNode.size()); + + + // remove the current node from the set + cloneRelatedLimNodes.erase(cloneRelatedLimNodesIt); + } + + + updateMemoryStat(config); + common::WriteMsg::write(WriteMsg::mlDebug, "Debug: Computing CI took %d (1/100s)\n", common::getProcessUsedTime().user - time.user); + } + + + void DuplicatedCodeMiner::calculateCLC_LDC() + { + auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("calculateCLC_LDC()"); + common::timestat time = common::getProcessUsedTime(); + + // Calculate the clone covered line intervals for each LIM node + + map>> coveredLinesMap; + + + for (auto cloneClassIter = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIter != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIter) + { + auto length = lengths[cloneClassIter->getId()]; + for (auto cloneInstanceIter = cloneClassIter->getItemsListIteratorBegin(); cloneInstanceIter != cloneClassIter->getItemsListIteratorEnd(); ++cloneInstanceIter) + { + auto startPosition = positions[cloneInstanceIter->getId()]; + + // Collect the lines for one instance into a separate container as we have to merge + // the ranges not to get logical line coverage before we add it to the coveredLinesMap + + map>> oneInstanceCoveredLinesMap; + + for (size_t index = startPosition; index < startPosition + length; ++index) + { + const auto nodeInfo = serializationData.nodeInfoSequence[index]; + if (nodeInfo != nullptr) + { + NodeId limNodeId = nodeInfo->getLimNodeId(); + if (limNodeId != 0) + oneInstanceCoveredLinesMap[limNodeId][nodeInfo->getPath()].insert(boost::icl::discrete_interval::closed(nodeInfo->getLine(), nodeInfo->getEndLine())); + + } + } + + // Merge the ranges for each LIM node to convert the logical line coverage to simple line coverage + for (const auto& covereageInfo : oneInstanceCoveredLinesMap) + { + for (const auto& fileCoverageInfo : covereageInfo.second) + { + unsigned firstStart = fileCoverageInfo.second.begin()->lower(); + unsigned lastEnd = fileCoverageInfo.second.rbegin()->upper(); +/* // Debug + if (fileCoverageInfo.second.size() > 1) + { + printf("Merge:\n"); + printf("LimId:%d\n", covereageInfo.first); + printf(" - %s\n", ASTNodeInfo::getStringPath(fileCoverageInfo.first).c_str()); + printf(" Begin: %d End: %d\n", firstStart, lastEnd); + } +*/ + coveredLinesMap[covereageInfo.first][fileCoverageInfo.first].insert(boost::icl::discrete_interval::closed(firstStart, lastEnd)); + + } + } + } + } + + updateMemoryStat(config); + +/* + // Debug + for (const auto& covereageInfo : coveredLinesMap) + { + printf("LimId:%d\n", covereageInfo.first); + for (const auto& fileCoverageInfo : covereageInfo.second) + { + printf(" - %s\n", ASTNodeInfo::getStringPath(fileCoverageInfo.first).c_str()); + for (const auto& interval : fileCoverageInfo.second) + { + //cout << interval << endl; + stringstream tempsstream; + tempsstream << interval; + + printf(" %s\n", tempsstream.str().c_str()); + } + } + } +*/ + set> cloneRelatedLimNodes; + + for (const auto& sourceCodeElementCoverage : coveredLinesMap) + cloneRelatedLimNodes.insert({ -getLimNodeDepth(sourceCodeElementCoverage.first), sourceCodeElementCoverage.first }); + + // Add the corresponding component nodes too + for (const auto& cloneRelatedLimNodeInfo : cloneRelatedLimNodes) + { + NodeId currentLimNodeId = cloneRelatedLimNodeInfo.second; + auto& currentLimNode = static_cast(limFact->getRef(currentLimNodeId)); + for (auto componentIt = currentLimNode.getBelongsToListIteratorBegin(); componentIt != currentLimNode.getBelongsToListIteratorEnd(); ++componentIt) + { + const NodeId componentId = componentIt->getId(); + // Copy the covered lines to the components + for (const auto& coveredLinesByPath : coveredLinesMap[currentLimNodeId]) + coveredLinesMap[componentId][coveredLinesByPath.first] += coveredLinesByPath.second; + + // Add the component nodes with a positive depth to be sure that they will be processed after all other nodes + // Since the component tree is flat (all but the system component is on level 1. + cloneRelatedLimNodes.insert({1 , componentId}); + } + } + + updateMemoryStat(config); + + // Calculate CLC for the LIM elements and aggregate the coverage infos to the parents + while (!cloneRelatedLimNodes.empty()) + { + auto cloneRelatedLimNodesIt = cloneRelatedLimNodes.begin(); + int currentDepth = cloneRelatedLimNodesIt->first; + NodeId currentLimNodeId = cloneRelatedLimNodesIt->second; + NodeId parentNodeId = getLimNodeParent(currentLimNodeId); + + const auto& coveredLinesOfTheCurentLIMNode = coveredLinesMap[currentLimNodeId]; + + if (parentNodeId != 0) + { + // Add covered lines to the parent + for (const auto& coveredLinesByPath : coveredLinesOfTheCurentLIMNode) + coveredLinesMap[parentNodeId][coveredLinesByPath.first] += coveredLinesByPath.second; + + // add the parent to the set + cloneRelatedLimNodes.insert({currentDepth + 1, parentNodeId }); + } + + // Add the covered ranges to get the full coverage + int coveredSize = 0; + for (const auto& coverdLinesByPath : coveredLinesOfTheCurentLIMNode) + coveredSize += length(coverdLinesByPath.second); + + + int TLOC = 0; + const auto& limNode = limFact->getRef(currentLimNodeId); + if (columbus::lim::asg::Common::getIsScope(limNode)) + TLOC = static_cast(limNode).getTLOC(); + else if (columbus::lim::asg::Common::getIsComponent(limNode)) + TLOC = static_cast(limNode).getTLOC(); + +/* // Debug + printf("LimId:%d (%d) : TLOC:%d Covered:%d (%f)\n", currentLimNodeId, currentDepth, TLOC, coveredSize, TLOC == 0 ? 0.0 : (double)coveredSize / TLOC); +*/ + + // Set the CI metric for LIM element + if (getIsNeeded("CLC")) + if (TLOC != 0) + graphsupport::setMetricFloat(graph, + lim2graph::VisitorGraphConverter::determineNodeName(currentLimNodeId), + "CLC", + (double)coveredSize / TLOC); + + if (getIsNeeded("LDC")) + graphsupport::setMetricInt(graph, + lim2graph::VisitorGraphConverter::determineNodeName(currentLimNodeId), + "LDC", + coveredSize); + + // remove the current node from the set + cloneRelatedLimNodes.erase(cloneRelatedLimNodesIt); + } + + + common::WriteMsg::write(WriteMsg::mlDebug, "Debug: Computing CLC and LDC took %d (1/100s)\n", common::getProcessUsedTime().user - time.user); + } + + void DuplicatedCodeMiner::calculateCLLC_LLDC() + { + auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("calculateCLLC()"); + common::timestat time = common::getProcessUsedTime(); + + // Calculate the clone covered line intervals for each LIM node + + map>> coveredLinesMap; + + + for (auto cloneClassIter = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIter != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIter) + { + auto length = lengths[cloneClassIter->getId()]; + for (auto cloneInstanceIter = cloneClassIter->getItemsListIteratorBegin(); cloneInstanceIter != cloneClassIter->getItemsListIteratorEnd(); ++cloneInstanceIter) + { + auto startPosition = positions[cloneInstanceIter->getId()]; + for (size_t index = startPosition; index < startPosition + length; ++index) + { + const auto nodeInfo = serializationData.nodeInfoSequence[index]; + if (nodeInfo != nullptr) + { + NodeId limNodeId = nodeInfo->getLimNodeId(); + if (limNodeId != 0) + { + auto& lineSet = coveredLinesMap[limNodeId][nodeInfo->getPath()]; + lineSet.insert(boost::icl::discrete_interval::closed(nodeInfo->getLine(), nodeInfo->getLine())); + lineSet.insert(boost::icl::discrete_interval::closed(nodeInfo->getEndLine(), nodeInfo->getEndLine())); + + if (nodeInfo->getExtraLines() != nullptr) + for (auto extraLine : *nodeInfo->getExtraLines()) + lineSet.insert(boost::icl::discrete_interval::closed(extraLine, extraLine)); + + } + } + } + } + } + + updateMemoryStat(config); + + +/* // Debug + for (const auto& covereageInfo : coveredLinesMap) + { + printf("LimId:%d\n", covereageInfo.first); + for (const auto& fileCoverageInfo : covereageInfo.second) + { + printf(" - %s\n", ASTNodeInfo::getStringPath(fileCoverageInfo.first).c_str()); + for (const auto& interval : fileCoverageInfo.second) + { + //cout << interval << endl; + stringstream tempsstream; + tempsstream << interval; + + printf(" %s\n", tempsstream.str().c_str()); + } + } + } +*/ + set> cloneRelatedLimNodes; + + for (const auto& sourceCodeElementCoverage : coveredLinesMap) + cloneRelatedLimNodes.insert({ -getLimNodeDepth(sourceCodeElementCoverage.first), sourceCodeElementCoverage.first }); + + // Add the corresponding component nodes too + for (const auto& cloneRelatedLimNodeInfo : cloneRelatedLimNodes) + { + NodeId currentLimNodeId = cloneRelatedLimNodeInfo.second; + auto& currentLimNode = static_cast(limFact->getRef(currentLimNodeId)); + for (auto componentIt = currentLimNode.getBelongsToListIteratorBegin(); componentIt != currentLimNode.getBelongsToListIteratorEnd(); ++componentIt) + { + const NodeId componentId = componentIt->getId(); + // Copy the covered lines to the components + for (const auto& coveredLinesByPath : coveredLinesMap[currentLimNodeId]) + coveredLinesMap[componentId][coveredLinesByPath.first] += coveredLinesByPath.second; + + // Add the component nodes with a positive depth to be sure that they will be processed after all other nodes + // Since the component tree is flat (all but the system component is on level 1. + cloneRelatedLimNodes.insert({1 , componentId}); + } + } + + updateMemoryStat(config); + + // Calculate CLLC for the LIM elements and aggregate the coverage infos to the parents + while (!cloneRelatedLimNodes.empty()) + { + auto cloneRelatedLimNodesIt = cloneRelatedLimNodes.begin(); + int currentDepth = cloneRelatedLimNodesIt->first; + NodeId currentLimNodeId = cloneRelatedLimNodesIt->second; + NodeId parentNodeId = getLimNodeParent(currentLimNodeId); + + const auto& coveredLinesOfTheCurentLIMNode = coveredLinesMap[currentLimNodeId]; + + if (parentNodeId != 0) + { + // Add covered lines to the parent + for (const auto& coveredLinesByPath : coveredLinesOfTheCurentLIMNode) + coveredLinesMap[parentNodeId][coveredLinesByPath.first] += coveredLinesByPath.second; + + // add the parent to the set + cloneRelatedLimNodes.insert({currentDepth + 1, parentNodeId }); + } + + // Add the covered ranges to get the full coverage + int coveredSize = 0; + for (const auto& coverdLinesByPath : coveredLinesOfTheCurentLIMNode) + coveredSize += length(coverdLinesByPath.second); + + + int TLLOC = 0; + const auto& limNode = limFact->getRef(currentLimNodeId); + if (columbus::lim::asg::Common::getIsScope(limNode)) + TLLOC = static_cast(limNode).getTLLOC(); + else if (columbus::lim::asg::Common::getIsComponent(limNode)) + TLLOC = static_cast(limNode).getTLLOC(); + +/* // Debug + printf("LimId:%d (%d) : TLLOC:%d Covered:%d (%f)\n", currentLimNodeId, currentDepth, TLLOC, coveredSize, TLLOC == 0 ? 0.0 : (double)coveredSize / TLLOC); +*/ + + // Set the CI metric for LIM element + if (getIsNeeded("CLLC")) + if (TLLOC != 0) + graphsupport::setMetricFloat(graph, + lim2graph::VisitorGraphConverter::determineNodeName(currentLimNodeId), + "CLLC", + (double)coveredSize / TLLOC); + if (getIsNeeded("LLDC")) + graphsupport::setMetricInt(graph, + lim2graph::VisitorGraphConverter::determineNodeName(currentLimNodeId), + "LLDC", + coveredSize); + + + // remove the current node from the set + cloneRelatedLimNodes.erase(cloneRelatedLimNodesIt); + } + + + common::WriteMsg::write(WriteMsg::mlDebug, "Debug: Computing CLLC and LLDC took %d (1/100s)\n", common::getProcessUsedTime().user - time.user); + } + + void DuplicatedCodeMiner::calculateCLLOC() + { + auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("calculateCLLOC()"); + common::timestat time = common::getProcessUsedTime(); + + for (auto cloneClassIter = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIter != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIter) + { + int lengthSum = 0; + for (auto cloneInstanceIter = cloneClassIter->getItemsListIteratorBegin(); cloneInstanceIter != cloneClassIter->getItemsListIteratorEnd(); ++cloneInstanceIter) + { + int cloneInstanceLength = cloneInstanceIter->getEndLine() - cloneInstanceIter->getLine() + 1; + graphsupport::setMetricInt(graph, + getGraphNameOfGenelogyNode(*cloneInstanceIter), + "CLLOC", + cloneInstanceLength); + + lengthSum += cloneInstanceLength; + } + + // TODO: Check the virtual instances + double clloc = (double)lengthSum / cloneClassIter->getInstances(); + + graphsupport::setMetricFloat(graph, + getGraphNameOfGenelogyNode(*cloneClassIter), + "CLLOC", + clloc); + + // At the moment there is only constant reference operator for the + // ListIterator class and it is faster to const_cast it than getting + // a non const referenc from the factory by its ID. + const_cast(*cloneClassIter).setClloc(clloc); + } + + common::WriteMsg::write(WriteMsg::mlDebug, "Debug: Computing CLLOC took %d (1/100s)\n", common::getProcessUsedTime().user - time.user); + } + + int calculateNDC(const std::string& path1,const std::string& path2) + { + boost::filesystem::path p1(path1); + boost::filesystem::path p2(path2); + boost::filesystem::path::iterator iterator1 = p1.begin(); + boost::filesystem::path::iterator iterator2 = p2.begin(); + + unsigned int dist=0; + while ((iterator1 != p1.end()) && (iterator2 != p2.end())) { + if ((*iterator1) != (*iterator2)) + break; + + iterator1++; + iterator2++; + } + + while (iterator1!=p1.end()) { + dist++; + iterator1++; + } + while (iterator2!=p2.end()) { + dist++; + iterator2++; + } + + //If the both file is not in the same directory the 2nd file change does not matter + if (dist > 1) + dist--; + + dist++; + return dist; + } + + + void DuplicatedCodeMiner::calculateNCR() + { + auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("calculateNCR()"); + common::timestat time = common::getProcessUsedTime(); +/* + // Debug + printfprintf("MaxNDC:%d\n", currentSystemMaxNDC); +*/ + + // Calculate NCR for clone classes + for (auto cloneClassIter = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIter != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIter) + { + vector instances; + for (auto cloneInstanceIter = cloneClassIter->getItemsListIteratorBegin(); cloneInstanceIter != cloneClassIter->getItemsListIteratorEnd(); ++cloneInstanceIter) + instances.push_back(&*cloneInstanceIter); + + int NDCSum = 0; + for (size_t CI1 = 0; CI1 < instances.size(); ++CI1) + for (size_t CI2 = CI1 + 1; CI2 < instances.size(); ++CI2) + { + int NDC = calculateNDC(instances[CI1]->getPath(), instances[CI2]->getPath()); + NDCSum += NDC; +/* + // Debug + printf("P1:%s\n", instances[CI1]->getPath().c_str()); + printf("P2:%s\n", instances[CI2]->getPath().c_str()); + printf("NDC:%d\n", NDC); +*/ + } + + double NCR = NDCSum; + NCR /= instances.size() * (instances.size() - 1) / 2; + NCR /= currentSystemMaxNDC; +/* + // Debug + printf("NCR:%f\n", NCR); +*/ + graphsupport::setMetricFloat(graph, + getGraphNameOfGenelogyNode(*cloneClassIter), + "NCR", + NCR); + + // At the moment there is only constant reference operator for the + // ListIterator class and it is faster to const_cast it than getting + // a non const referenc from the factory by its ID. + const_cast(*cloneClassIter).setNcrad(NCR); + } + + // Calculate NCR for components + map< /* LIM component */ NodeId, set> componentCloneClassMap; + + // Collect the clone classes for each direct clone instance related sourecode elements + for (auto cloneClassIter = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIter != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIter) + { + for (auto cloneInstanceIter = cloneClassIter->getItemsListIteratorBegin(); cloneInstanceIter != cloneClassIter->getItemsListIteratorEnd(); ++cloneInstanceIter) + { + const auto& correspondingSourceCodeElements = limNodeCloneInstanceMap[cloneInstanceIter->getId()]; + for (auto limNodeId : correspondingSourceCodeElements) + { + auto& currentLimNode = static_cast(limFact->getRef(limNodeId)); + for (auto componentIt = currentLimNode.getBelongsToListIteratorBegin(); componentIt != currentLimNode.getBelongsToListIteratorEnd(); ++componentIt) + componentCloneClassMap[componentIt->getId()].insert(&*cloneClassIter); + } + } + } + + // Since the component tree is flat we don't have to aggregate it, but just calculate it to the system component too + for (const auto& componentCloneClasses : componentCloneClassMap) + { + NodeId limComponentNodeId = componentCloneClasses.first; + const auto& cloneClassesOfTheComponent = componentCloneClasses.second; + + double NCR = 0; + for (auto CC : cloneClassesOfTheComponent) + NCR += CC->getNcrad(); + + NCR /= cloneClassesOfTheComponent.size(); + +/* + // Debug + printf("Component NCR:%f\n", NCR); +*/ + graphsupport::setMetricFloat(graph, + lim2graph::VisitorGraphConverter::determineNodeName(limComponentNodeId), + "NCR", + NCR); + + } + + // Set the NCR to INVALID for components, which do not contain clones + const auto& systemComponentNode = limFact->getComponentRootRef(); + for (auto componentIt = systemComponentNode.getContainsListIteratorBegin(); componentIt != systemComponentNode.getContainsListIteratorEnd(); ++componentIt) + if (componentCloneClassMap.find(componentIt->getId()) == componentCloneClassMap.end()) + graphsupport::setMetricFloat(graph, + lim2graph::VisitorGraphConverter::determineNodeName(componentIt->getId()), + "NCR", + nan("")); + + // Calculate NCR to to the system component + double systemNCR = 0.0; + for (auto cloneClassIter = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIter != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIter) + systemNCR += cloneClassIter->getNcrad(); + + systemNCR /= currentSystem->getCloneClassesSize(); + +/* + // Debug + printf("System NCR:%f\n", systemNCR); +*/ + graphsupport::setMetricFloat(graph, + lim2graph::VisitorGraphConverter::determineNodeName(limFact->getComponentRoot()), + "NCR", + systemNCR); + + common::WriteMsg::write(WriteMsg::mlDebug, "Debug: Computing NCR took %d (1/100s)\n", common::getProcessUsedTime().user - time.user); + } + + + void DuplicatedCodeMiner::calculateCE() + { + auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("calculateCE()"); + common::timestat time = common::getProcessUsedTime(); + + + // Collect incoming and outgoing references for each clone instance + for (auto cloneClassIter = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIter != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIter) + { + auto length = lengths[cloneClassIter->getId()]; + int CC_CE = 1; + for (auto cloneInstanceIter = cloneClassIter->getItemsListIteratorBegin(); cloneInstanceIter != cloneClassIter->getItemsListIteratorEnd(); ++cloneInstanceIter) + { + + set internalNodes; + bool fullFunctionClone = false; + NodeId startNodeId = 0; + NodeId startLimNodeId = 0; + + auto startPosition = positions[cloneInstanceIter->getId()]; + const auto& nodeInfo = serializationData.nodeInfoSequence[startPosition]; + if (nodeInfo != nullptr) + { + startNodeId = nodeInfo->getId(); + startLimNodeId = nodeInfo->getLimNodeId(); + } + + // check if it is a full function clone + int nodeKind = serializationData.nodeKindSequence[startPosition]; + if (((nodeKind & NodeMask::NodeTypeMask) == NodeType::Declaration) && + (((nodeKind & NodeMask::NodeKindMask) == clang::Decl::Kind::Function) || ((nodeKind & NodeMask::NodeKindMask) == clang::Decl::Kind::CXXMethod))) + { + fullFunctionClone = true; + } + + Key astKey = serializationData.nodeInfoSequence[startPosition]->getTUPath(); + for (size_t index = startPosition; index < startPosition + length; ++index) + { + const auto nodeInfo = serializationData.nodeInfoSequence[index]; + if (nodeInfo != nullptr) + internalNodes.insert(nodeInfo->getId()); + + } + + set outgoingRefs; + // collect to outgoing references + for (const auto nodeId : internalNodes) + { + const auto& refMap = serializationData.referencesMap[astKey]; + auto refIt = refMap.find(nodeId); + if (refIt != refMap.end()) + if (internalNodes.find(refIt->second) == internalNodes.end()) + outgoingRefs.insert(refIt->second); + } + +/* + // Debug + printf("Clone id: %u\n ", cloneInstanceIter->getId()); + printf("Outgoing refs:\n "); + for (const auto nodeId : outgoingRefs) + printf("%u ", nodeId); + printf("\n"); +*/ + set incomingRefs; + // collect to incoming references + for (const auto nodeId : internalNodes) + { + // For full function clones we skip the function node itself as the call edges of the + // the corresponding LIM node will be used to get calls across compilation units + if (fullFunctionClone && nodeId == startNodeId) + continue; + + const auto& inverseRefMap = serializationData.inverseReferencesMap[astKey]; + auto refIt = inverseRefMap.find(nodeId); + if (refIt != inverseRefMap.end()) + for (const auto externalNodeId : refIt->second) + { + + if (internalNodes.find(externalNodeId) == internalNodes.end()) + incomingRefs.insert(externalNodeId); + } + } +/* + // Debug + printf("Clone id: %u\n ", cloneInstanceIter->getId()); + printf("Incoming refs:\n"); + for (const auto nodeId : incomingRefs) + printf("%u ", nodeId); + printf("\n"); +*/ + // TODO: types, calls from other compilation units; + const string& clonePath = cloneInstanceIter->getPath(); + + int CE = 0; + + // Use the lim call edges for the incoming references if the clone is a full function + if (fullFunctionClone) + { + + if (lim::asg::Common::getIsMethod(limFact->getRef(startLimNodeId))) + { + auto methodcallIt = limFact->getReverseEdges().constIteratorBegin(startLimNodeId, columbus::lim::asg::edkMethodCall_Method); + auto methodcallItEnd = limFact->getReverseEdges().constIteratorEnd(startLimNodeId, columbus::lim::asg::edkMethodCall_Method); + while(methodcallIt != methodcallItEnd) + { + const lim::asg::base::Base& methodCall = *methodcallIt; + auto methodIt = limFact->getReverseEdges().constIteratorBegin(methodCall.getId(), columbus::lim::asg::edkMethod_Calls); + auto methodItEnd = limFact->getReverseEdges().constIteratorEnd(methodCall.getId(), columbus::lim::asg::edkMethod_Calls); + + while(methodIt != methodItEnd) + { + const lim::asg::logical::Method& callerMethod = static_cast(*methodIt); + + auto containedInItEnd = callerMethod.getIsContainedInListIteratorAssocEnd(); + for(auto containedInIt = callerMethod.getIsContainedInListIteratorAssocBegin(); containedInIt != containedInItEnd; ++containedInIt) + CE += calculateNDC(clonePath, columbus::lim::asg::Common::getFullPath((*containedInIt)).c_str()); + + ++methodIt; + } + ++methodcallIt; + } + } + else + { +/* + // DEBUG + printf("FunctionClone (%d) with not method LIM node: LIM root nodeid:%d nodekind:%s\n", + cloneInstanceIter->getId(), + startLimNodeId, + lim::asg::Common::toString(limFact->getRef(startLimNodeId).getNodeKind()).c_str()); +*/ + } + } + + // Weight the outgoing references + for (const auto outgoingRef : outgoingRefs) + { + const string& referencePath = ASTNodeInfo::getStringPath(serializationData.nodeReferencePathMap[astKey][outgoingRef]); + string relativeReferencePath = referencePath.c_str(); + CE += calculateNDC(clonePath, relativeReferencePath); +/* + // DEBUG + printf("O: CP: %s RefPath: %s CE: %d\n", clonePath.c_str(), relativeReferencePath.c_str(), CE); +*/ + } + + // Weight the incoming references + for (const auto incomingRef : incomingRefs) + { + const string& referencePath = ASTNodeInfo::getStringPath(serializationData.nodeReferencePathMap[astKey][incomingRef]); + string relativeReferencePath = referencePath.c_str(); + CE += calculateNDC(clonePath, relativeReferencePath); +/* + // DEBUG + printf("I: CP: %s RefPath: %s CE: %d\n", clonePath.c_str(), relativeReferencePath.c_str(), CE); +*/ + } + + + graphsupport::setMetricInt(graph, + getGraphNameOfGenelogyNode(*cloneInstanceIter), + "CE", + CE); + + CC_CE += CE; + + // At the moment there is only constant reference operator for the + // ListIterator class and it is faster to const_cast it than getting + // a non const referenc from the factory by its ID. + const_cast(*cloneInstanceIter).setCe(CE); + } + + graphsupport::setMetricInt(graph, + getGraphNameOfGenelogyNode(*cloneClassIter), + "CE", + CC_CE); + + // At the moment there is only constant reference operator for the + // ListIterator class and it is faster to const_cast it than getting + // a non const referenc from the factory by its ID. + const_cast(*cloneClassIter).setCe(CC_CE); + + + } + + common::WriteMsg::write(WriteMsg::mlDebug, "Debug: Computing CE took %d (1/100s)\n", common::getProcessUsedTime().user - time.user); + } + + + void DuplicatedCodeMiner::calculateCEE() + { + auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("calculateCEE()"); + common::timestat time = common::getProcessUsedTime(); + + for (auto cloneClassIter = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIter != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIter) + { + if (cloneClassIter->getIsVirtual()) + continue; + + genealogy::CloneClass& cloneClass = const_cast(*cloneClassIter); + + // TODO: Check if the virtual instances are calculated into the instances attribute! + double eliminationEffort = cloneClass.getCe() * cloneClass.getNcrad() * cloneClass.getInstances(); + + graphsupport::setMetricFloat(graph, + getGraphNameOfGenelogyNode(cloneClass), + "CEE", + eliminationEffort); + + cloneClass.setEffort(eliminationEffort); + } + + + // Calculate CEE for components + map< /* LIM component */ NodeId, set> componentCloneClassMap; + + // Collect the clone classes for each component + for (auto cloneClassIter = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIter != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIter) + { + for (auto cloneInstanceIter = cloneClassIter->getItemsListIteratorBegin(); cloneInstanceIter != cloneClassIter->getItemsListIteratorEnd(); ++cloneInstanceIter) + { + const auto& correspondingSourceCodeElements = limNodeCloneInstanceMap[cloneInstanceIter->getId()]; + for (auto limNodeId : correspondingSourceCodeElements) + { + auto& currentLimNode = static_cast(limFact->getRef(limNodeId)); + for (auto componentIt = currentLimNode.getBelongsToListIteratorBegin(); componentIt != currentLimNode.getBelongsToListIteratorEnd(); ++componentIt) + componentCloneClassMap[componentIt->getId()].insert(&*cloneClassIter); + } + } + } + + // Set the CEE for the components + for (const auto& cloneClasses : componentCloneClassMap) + { + double eliminationEffort = 0; + for (const auto cloneClassPtr : cloneClasses.second) + eliminationEffort += cloneClassPtr->getEffort(); + + graphsupport::setMetricFloat(graph, + lim2graph::VisitorGraphConverter::determineNodeName(cloneClasses.first), + "CEE", + eliminationEffort); + + componentMetrics[cloneClasses.first].CEE = eliminationEffort; + } + + // set CEE for the system component + double eliminationEffort = 0; + for (auto cloneClassIter = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIter != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIter) + eliminationEffort += cloneClassIter->getEffort(); + + graphsupport::setMetricFloat(graph, + lim2graph::VisitorGraphConverter::determineNodeName(limFact->getComponentRoot()), + "CEE", + eliminationEffort); + + componentMetrics[limFact->getComponentRoot()].CEE = eliminationEffort; + + common::WriteMsg::write(WriteMsg::mlDebug, "Debug: Computing CEE took %d (1/100s)\n", common::getProcessUsedTime().user - time.user); + } + + void DuplicatedCodeMiner::calculateCEG() + { + auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("calculateCEG()"); + common::timestat time = common::getProcessUsedTime(); + + for (auto cloneClassIter = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIter != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIter) + { + if (cloneClassIter->getIsVirtual()) + continue; + + genealogy::CloneClass& cloneClass = const_cast(*cloneClassIter); + + double cloneEliminationGain; + + if (cloneClass.getEffort() < std::numeric_limits::epsilon()) + cloneEliminationGain = nan(""); + else + cloneEliminationGain = cloneClass.getRisk() / cloneClass.getEffort(); + + graphsupport::setMetricFloat(graph, + getGraphNameOfGenelogyNode(cloneClass), + "CEG", + cloneEliminationGain); + + cloneClass.setGain(cloneEliminationGain); + } + + /* (((1 / (1+ e^(-2*CR/ln(CEE)) )*100)-50)*2) */ + for (const auto& cMetrics : componentMetrics) + { + double cloneEliminationGain; + + if (cMetrics.second.CEE < std::numeric_limits::epsilon()) + cloneEliminationGain = nan(""); + else + cloneEliminationGain = ((100.0 / ( 1.0 + exp(-2.0 * cMetrics.second.CR / log(cMetrics.second.CEE)))) - 50.0) * 2.0; + + graphsupport::setMetricFloat(graph, + lim2graph::VisitorGraphConverter::determineNodeName(cMetrics.first), + "CEG", + cloneEliminationGain); + } + + common::WriteMsg::write(WriteMsg::mlDebug, "Debug: Computing CEG took %d (1/100s)\n", common::getProcessUsedTime().user - time.user); + } + + void DuplicatedCodeMiner::calculateCR() + { + auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("calculateCR()"); + common::timestat time = common::getProcessUsedTime(); + + for (auto cloneClassIter = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIter != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIter) + { + if (cloneClassIter->getIsVirtual()) + continue; + + genealogy::CloneClass& cloneClass = const_cast(*cloneClassIter); + + // TODO: Check if the virtual instances are calculated into the instances attribute! + double cloneRisk = cloneClass.getClloc() * cloneClass.getInstances() * cloneClass.getCco() * cloneClass.getNcrad() * cloneClass.getCv(); + + graphsupport::setMetricFloat(graph, + getGraphNameOfGenelogyNode(cloneClass), + "CR", + cloneRisk); + + cloneClass.setRisk(cloneRisk); + } + + + // Calculate CR for components + map< /* LIM component */ NodeId, set> componentCloneClassMap; + + // Collect the clone classes for each component + for (auto cloneClassIter = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIter != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIter) + { + for (auto cloneInstanceIter = cloneClassIter->getItemsListIteratorBegin(); cloneInstanceIter != cloneClassIter->getItemsListIteratorEnd(); ++cloneInstanceIter) + { + const auto& correspondingSourceCodeElements = limNodeCloneInstanceMap[cloneInstanceIter->getId()]; + for (auto limNodeId : correspondingSourceCodeElements) + { + auto& currentLimNode = static_cast(limFact->getRef(limNodeId)); + for (auto componentIt = currentLimNode.getBelongsToListIteratorBegin(); componentIt != currentLimNode.getBelongsToListIteratorEnd(); ++componentIt) + componentCloneClassMap[componentIt->getId()].insert(&*cloneClassIter); + } + } + } + + // Set the CR for the components + for (const auto& cloneClasses : componentCloneClassMap) + { + double cloneRisk = 0; + for (const auto cloneClassPtr : cloneClasses.second) + cloneRisk += cloneClassPtr->getRisk(); + + const auto& limComponentNode = static_cast(limFact->getRef(cloneClasses.first)); + cloneRisk /= limComponentNode.getTLLOC(); + + graphsupport::setMetricFloat(graph, + lim2graph::VisitorGraphConverter::determineNodeName(cloneClasses.first), + "CR", + cloneRisk); + + componentMetrics[cloneClasses.first].CR = cloneRisk; + } + + // set CR for the system component + double cloneRisk = 0; + for (auto cloneClassIter = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIter != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIter) + cloneRisk += cloneClassIter->getRisk(); + + const auto& limSystemComponentNode = static_cast(limFact->getRef(limFact->getComponentRoot())); + cloneRisk /= limSystemComponentNode.getTLLOC(); + + graphsupport::setMetricFloat(graph, + lim2graph::VisitorGraphConverter::determineNodeName(limFact->getComponentRoot()), + "CR", + cloneRisk); + + componentMetrics[limFact->getComponentRoot()].CR = cloneRisk; + + + + common::WriteMsg::write(WriteMsg::mlDebug, "Debug: Computing CR took %d (1/100s)\n", common::getProcessUsedTime().user - time.user); + } + + void DuplicatedCodeMiner::calculateCA() + { + auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("calculateCA()"); + common::timestat time = common::getProcessUsedTime(); + + for (auto cloneClassIter = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIter != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIter) + { + if (cloneClassIter->getIsVirtual()) + continue; + + for (auto cloneInstanceIter = cloneClassIter->getItemsListIteratorBegin(); cloneInstanceIter != cloneClassIter->getItemsListIteratorEnd(); ++cloneInstanceIter) + { + auto &cloneInstance = const_cast(*cloneInstanceIter); + + if (cloneInstance.getIsVirtual()) + continue; + + if (!cloneInstance.getPrevIsEmpty()) + { + const auto& prevInstance = static_cast(*cloneInstance.getPrevListIteratorBegin()); + cloneInstance.setCa(prevInstance.getCa() + 1); + } + else + { + cloneInstance.setCa(1); + } + + graphsupport::setMetricInt(graph, + getGraphNameOfGenelogyNode(cloneInstance), + "CA", + cloneInstance.getCa()); + + } + + auto &cloneClass = const_cast(*cloneClassIter); + if (!cloneClass.getPrevIsEmpty()) + { + const auto& prevClass = static_cast(*cloneClass.getPrevListIteratorBegin()); + cloneClass.setCa(prevClass.getCa() + 1); + } + else + { + cloneClass.setCa(1); + } + + + graphsupport::setMetricInt(graph, + getGraphNameOfGenelogyNode(cloneClass), + "CA", + cloneClass.getCa()); + } + + + common::WriteMsg::write(WriteMsg::mlDebug, "Debug: Computing CA took %d (1/100s)\n", common::getProcessUsedTime().user - time.user); + } + + void DuplicatedCodeMiner::calculateCV() + { + auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("calculateCV()"); + common::timestat time = common::getProcessUsedTime(); + + for (auto cloneClassIter = currentSystem->getCloneClassesListIteratorBegin(); cloneClassIter != currentSystem->getCloneClassesListIteratorEnd(); ++cloneClassIter) + { + if (cloneClassIter->getIsVirtual()) + continue; + + bool hasSmell = 0; + double cvSum = 0.0; + + for (auto cloneInstanceIter = cloneClassIter->getItemsListIteratorBegin(); cloneInstanceIter != cloneClassIter->getItemsListIteratorEnd(); ++cloneInstanceIter) + { + auto &cloneInstance = const_cast(*cloneInstanceIter); + + if (cloneInstance.getIsVirtual()) + continue; + + if (!cloneInstance.getPrevIsEmpty()) + { + const auto& prevInstance = static_cast(*cloneInstance.getPrevListIteratorBegin()); + + // check if there were changes in structure + if ((cloneInstance.getEndLine() - cloneInstance.getLine()) != (prevInstance.getEndLine() - prevInstance.getLine()) || + (cloneInstance.getCco() != cloneInstance.getCco())) + { + cloneInstance.setCvMetricVariability(prevInstance.getCvMetricVariability() + 1); + } + else + { + cloneInstance.setCvMetricVariability(prevInstance.getCvMetricVariability()); + } + } + else + { + cloneInstance.setCvMetricVariability(0); + } + + double cv = (1.0 + cloneInstance.getCvMetricVariability()) / cloneInstance.getCa(); + cloneInstance.setCv(cv); + cvSum += cv; + + if (cloneInstance.getCloneSmellType() != columbus::genealogy::cstNone) + hasSmell = 1; + + graphsupport::setMetricFloat(graph, + getGraphNameOfGenelogyNode(cloneInstance), + "CV", + cv); + + } + + + auto &cloneClass = const_cast(*cloneClassIter); + if (!cloneClass.getPrevIsEmpty()) + { + const auto& prevClass = static_cast(*cloneClass.getPrevListIteratorBegin()); + cloneClass.setCvCiSmells(prevClass.getCvCiSmells() + hasSmell); + } + else + { + cloneClass.setCvCiSmells(hasSmell); + } + + double ccCV = ((double)cloneClass.getCvCiSmells()) / cloneClass.getCa() + (cvSum / cloneClass.getInstances()); + cloneClass.setCv(ccCV); + + + graphsupport::setMetricFloat(graph, + getGraphNameOfGenelogyNode(cloneClass), + "CV", + ccCV); + + } + + common::WriteMsg::write(WriteMsg::mlDebug, "Debug: Computing CV took %d (1/100s)\n", common::getProcessUsedTime().user - time.user); + } + + + + void DuplicatedCodeMiner::calculateMetrics() + { + auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("calculateMetrics()"); + common::timestat time = common::getProcessUsedTime(); + common::WriteMsg::write(CMSG_COMPUTING_METRICS); + + // Collect the component LIM nodes and initialize the metric values to zero + const auto& systemComponentNode = limFact->getComponentRootRef(); + for (auto componentIt = systemComponentNode.getContainsListIteratorBegin(); componentIt != systemComponentNode.getContainsListIteratorEnd(); ++componentIt) + { + auto& metrics = componentMetrics[componentIt->getId()]; + metrics.CR = metrics.CEE = 0.0; + } + + if (getIsNeeded("CC")) + calculateCC(); + + if (getIsNeeded("CI")) + calculateCI(); + + if (getIsNeeded("CCL")) + calculateCCL(); + + if (getIsNeeded("CLLOC")) + calculateCLLOC(); + + if (getIsNeeded("CCO")) + calculateCCO(); + + if (getIsNeeded("CLLC") || getIsNeeded("LLDC")) + calculateCLLC_LLDC(); + + if (getIsNeeded("CLC") || getIsNeeded("LDC")) + calculateCLC_LDC(); + + if (getIsNeeded("NCR")) + calculateNCR(); + + if (getIsNeeded("CE")) + calculateCE(); + + + config.stat.calculateMetricsTime += common::getProcessUsedTime().user - time.user; + common::WriteMsg::write(CMSG_DONE_D); + + } + + + void DuplicatedCodeMiner::calculateEvolutionDependentMetrics() + { + auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("calculateEvolutionDependentMetrics()"); + common::timestat time = common::getProcessUsedTime(); + common::WriteMsg::write(CMSG_COMPUTING_EVOLUTION_METRICS); + + if (getIsNeeded("CA")) + calculateCA(); + + if (getIsNeeded("CV")) + calculateCV(); + + if (getIsNeeded("CEE")) + calculateCEE(); + + if (getIsNeeded("CR")) + calculateCR(); + + if (getIsNeeded("CEG")) + calculateCEG(); + + // The component metrics are no longer needed. + componentMetrics.clear(); + + config.stat.calculateMetricsTime += common::getProcessUsedTime().user - time.user; + common::WriteMsg::write(CMSG_DONE_D); + } + + + void DuplicatedCodeMiner::getLimNodeParents(NodeId limId, std::set& parents) + { + if (limId != 0) + { + columbus::lim::asg::EdgeKind edgeKind = columbus::lim::asg::edkScope_HasMember; + + if (columbus::lim::asg::Common::getIsComponent(limFact->getRef(limId))) + edgeKind = columbus::lim::asg::edkComponent_Contains; + + for (auto itParent = limFact->getReverseEdges().constIteratorBegin(limId, edgeKind); + itParent != limFact->getReverseEdges().constIteratorEnd(limId, edgeKind); + ++itParent) + { + parents.insert(itParent->getId()); + getLimNodeParents(itParent->getId(), parents); + } + } + } + + NodeId DuplicatedCodeMiner::getLimNodeParent(NodeId limId) const + { + if (limId != 0) + { + columbus::lim::asg::EdgeKind edgeKind = columbus::lim::asg::edkScope_HasMember; + + if (columbus::lim::asg::Common::getIsComponent(limFact->getRef(limId))) + edgeKind = columbus::lim::asg::edkComponent_Contains; + + auto itParent = limFact->getReverseEdges().constIteratorBegin(limId, edgeKind); + + if (itParent != limFact->getReverseEdges().constIteratorEnd(limId, edgeKind)) + return itParent->getId(); // return the first + } + return 0; + } + + + void DuplicatedCodeMiner::sortNodesByType(const NodeIDMaps &idMaps + , std::vector &nodes + , std::vector &declarations + , std::vector &statements) + { + for(auto node : nodes) + { + const auto& nodeInfoIt = idMaps.id2node.find(node); + if (nodeInfoIt != idMaps.id2node.end()) + { + if (nodeInfoIt->second.second == AstNodeType::STMT) + statements.push_back(static_cast(nodeInfoIt->second.first)); + else if(nodeInfoIt->second.second == AstNodeType::DECL) + declarations.push_back(static_cast(nodeInfoIt->second.first)); + } + } + } + +} + + diff --git a/cl/DCF-CPP/src/main.cpp b/cl/DCF-CPP/src/main.cpp new file mode 100644 index 0000000..7b13183 --- /dev/null +++ b/cl/DCF-CPP/src/main.cpp @@ -0,0 +1,338 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + + +#define PROGRAM_NAME "DuplicatedCodeFinder" +#define EXECUTABLE_NAME "DuplicatedCodeFinder" + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "../inc/messages.h" +#include "../inc/Config.h" +#include "../inc/dcm.h" + +using namespace std; +using namespace common; +using namespace columbus; + + +Config config; + +//------------------------------------------------------- +// Callback methods for argument processing + +static bool ppList (const Option *o, char *argv[]) { + config.fList = argv[0]; + return true; +} + +static bool ppRul (const Option *o, char *argv[]) { + config.rul_str = argv[0]; + return true; +} + +static bool ppRulConfig (const Option *o, char *argv[]) { + config.rulConfig = argv[0]; + return true; +} + +static bool ppMetrics (const Option *o, char *argv[]) { + config.metrics = true; + return true; +} + +static bool ppOut (const Option *o, char *argv[]) { + config.dcout = argv[0]; + return true; +} + +static bool ppPathLower (const Option *o, char *argv[]) { + config.lp = true; + return true; +} + +static bool ppLines (const Option *o, char *argv[]) { + config.minLines = boost::lexical_cast(argv[0]); + return true; +} + +static bool ppNodes (const Option *o, char *argv[]) { + config.minAsgNodes = boost::lexical_cast(argv[0]); + return true; +} + +static bool ppOccur (const Option *o, char *argv[]) { + config.minOccur = boost::lexical_cast(argv[0]); + return true; +} + +static bool ppGenealogy (const Option *o, char *argv[]) { + config.genealogyFilename = argv[0]; + return true; +} + +static void ppFile(char *filename) { + + config.files.push_back(filename); +} + +static bool ppLimFile(const Option *o, char *argv[]) { + config.limFileName = argv[0]; + return true; +} + +static bool ppGraph (const Option *o, char *argv[]) { + config.graphFilename = argv[0]; + return true; +} + +static bool ppPatternFilter (const Option *o, char *argv[]) { + config.patternMaxSingleLength = boost::lexical_cast(argv[0]); + config.patternMinFullLength = boost::lexical_cast(argv[1]); + return true; +} + +static bool ppFOut (const Option *o, char *argv[]) { + config.dcFout = argv[0]; + return true; +} + +static bool ppMultipleAsgRoot(const Option *o, char *argv[]) { + config.singleAsgRoot = false; + return true; +} + +static bool ppExportRul(const Option *o, char *argv[]) { + config.exportRul = true; + return true; +} + + +static bool ppFc(const Option *o, char *argv[]) { + config.ofc = true; + return true; +} + +static bool ppFst (const Option *o, char *argv[]) { + config.statementFilter = false; + return true; +} + +static bool ppFilterPath (const Option *o, char *argv[]) { + config.filterfile = argv[0]; + return true; +} + +const common::Option OPTIONS_OBJ [] = { + CL_LIM + { false, "-metrics", 0, "", 0, OT_WC, ppMetrics, NULL, "Calculate clone metrics."}, + { false, "-out", 1, "filename", 0, OT_WC, ppOut, NULL, "File into which the list of the clones is written. If it is not specified then the list will be written to the standard output."}, + { false, "-lowerpath", 0, "", 0, OT_NONE, ppPathLower, NULL, "Convert all the paths to lower case."}, + { false, "-minlines", 1, "number", 0, OT_WC, ppLines, NULL, "The minimum number of lines of each duplication. Default value is 10."}, + { false, "-minnodes", 1, "number", 0, OT_WC, ppNodes, NULL, "The minimum number of ASG nodes of each duplication. Default value is 20."}, + { false, "-minoccur", 1, "number", 0, OT_WC, ppOccur, NULL, "The minimum number of occurences of each kind of duplication. Default value is 2."}, + + { false, "-genealogy", 1, "filename", 0, OT_WC, ppGenealogy, NULL, "The geneology file, which contains historical information about the clones."}, + + { false, "-graph", 1, "filename", 0, OT_WC, ppGraph, NULL, "Save structured result of the clones and metrics in binary graph format."}, + { false, "-patternfilterlog",1, "filename", 0, OT_WC, ppFOut, NULL, "Save the source code positions of the filtered source elements to the given file. If it is not set then the list will be written to the standard out."}, + { false, "-patternfilter", 2, "number number", 0, OT_WS, ppPatternFilter,NULL, "Enable pattern filter with the given parameters. The first number is the maximum length (default value is 10) of a single pattern " + "and the second number is the minimum length (default value is 100) of the whole repeating patter series to be detected."}, + { false, "-multipleasgroot", 0, "", 0, OT_WC, ppMultipleAsgRoot, NULL,"Clone instances can have multiple ASG root."}, + { false, "-onlyfunctionclone", 0, "", 0, OT_WC, ppFc, NULL,"Clones are detected only inside the functions."}, + { false, "-statementNotReq", 0, "", 0, OT_WC, ppFst, NULL,"Not filter clone instance which has not contained statement."}, + CL_RUL_AND_RULCONFIG("DCF.rul") + CL_EXPORTRUL + CL_INPUT_LIST + CL_FLTP + COMMON_CL_ARGS +}; + +unique_ptr initValues() +{ + unique_ptr rulHandler; + //------------------------ Loading files --------------------------- + if (config.rul_str.empty()) { + std::string rulFile; + rulFile = "DCF.rul"; + config.rul_str = getExecutableProgramDir()+rulFile; + common::WriteMsg::write(CMSG_RUL_FILE_NOT_SET, config.rul_str.c_str()); + } + //trying to touch the .rul file + try { + if(!common::pathIsAbsolute(config.rul_str.c_str())) { + config.rul_str = getExecutableProgramDir() + config.rul_str; + } + // create rule handler + if(config.rulConfig.empty()) { + config.rulConfig = "cpp"; + } + rulHandler = make_unique(config.rul_str, config.rulConfig, "eng"); + } + catch (const columbus::Exception& e) + { + common::WriteMsg::write(CMSG_SIMPLE_STRING_TRANSMIT_ERR, e.toString().c_str()); + exit(-1); + } + common::WriteMsg::write(CMSG_RUL_FILE_FOUND, config.rul_str.c_str()); + + loadStringListFromFile(config.fList, config.files); + + if (!config.blockPaths.empty()) { + std::ifstream ifs(config.blockPaths.c_str()); + string line; + do { + getline(ifs, line); + if (!line.empty()) { + if (config.lp) + config.bpaths.push_back(boost::to_lower_copy(line)); + else + config.bpaths.push_back(line); + } + if (ifs.eof()) break; + } while (true); + } + + if (config.files.size() == 0) { + common::WriteMsg::write(CMSG_NO_INPUT_FILES); + Help(); + exit(common::retBadArgError); + } + + if (config.limFileName.empty()) { + common::WriteMsg::write(CMSG_NO_INPUT_LIM_FILE); + Help(); + exit(common::retBadArgError); + } + + common::WriteMsg::write(CMSG_THE_LIM_INPUT_FILE,config.limFileName.c_str()); + common::WriteMsg::write(CMSG_LINE_INFO_CASE , (config.lp ? CMSG_LINE_INFO_CASE_LOWERED : CMSG_LINE_INFO_CASE_DEFAULT)); + common::WriteMsg::write(CMSG_MINIMUM_NUMBER_OF_LINES,config.minLines); + common::WriteMsg::write(CMSG_MINIMUM_NUMBER_OF_ASG_NODES, config.minAsgNodes); + common::WriteMsg::write(CMSG_MAXIMUM_PATTERN_SIZE,config.patternMaxSingleLength); + common::WriteMsg::write(CMSG_MINIMUM_PATTERN_FULL_LENGTH, config.patternMinFullLength); + + return rulHandler; +} + + +static inline void setStartTime(uint64_t *time) { + timestat usedtime= getProcessUsedTime(); + *time= usedtime.user + usedtime.system; +} + +static inline void setElapsedTime(uint64_t *time) { + timestat usedtime= getProcessUsedTime(); + *time= usedtime.user + usedtime.system - *time; +} + + +int main(int argc, char* argv[]){ + int exit_code = EXIT_SUCCESS; + uint64_t time = 0; + WriteMsg::setAutomaticFlush(true); + + MAIN_BEGIN + + MainInit(argc, argv,"-"); + + if (config.files.empty() && config.fList.empty()) { + Help(); + exit(common::retBadArgError); + } + + setStartTime(&time); + unique_ptr rulHandler = initValues(); + + common::WriteMsg::write(CMSG_DETECTING_CODE_DUPLICATIONS ); + + DuplicatedCodeMiner dcm(config, rulHandler.get()); + dcm.setStatementFilter(config.statementFilter); + ofstream filterOutputStream;; + + if(config.dcFout.empty()) + { + common::WriteMsg::write(CMSG_FILTER_RESULT_REDIRECTED_TO_STANDARD_OUT); + dcm.setFilterOut(cout); + } + else + { + filterOutputStream.open(config.dcFout.c_str()); + if(filterOutputStream) + { + common::WriteMsg::write(CMSG_FILTER_RESULT_REDIRECTED_INTO_FILE, config.dcFout.c_str()); + dcm.setFilterOut(filterOutputStream); + } + else + { + common::WriteMsg::write(CMSG_FAILED_OPEN_FILE, config.dcFout.c_str()); + } + } + + //the main detecting clones + exit_code = dcm.dcminer(); + + if (exit_code == EXIT_SUCCESS) { + + if(!config.dcout.empty()) { + common::WriteMsg::write(CMSG_DUMPING_OUTPUT_TO_FILE, config.dcout.c_str()); + ofstream out(config.dcout.c_str()); + dcm.dumpLastSystem(out); + } + /** + * Eventually to the standard output as well + */ + if(config.dcout.empty()) { + common::WriteMsg::write(CMSG_DUMPING_OUTPUT_TO_STANDARD_OUTPUT); + dcm.dumpLastSystem(cout); + } + + + if(!config.graphFilename.empty()) { + dcm.exportGraph(config.graphFilename); + } + + common::WriteMsg::write(CMSG_DONE_N); + + dcm.saveGenealogy(); + + } + + setElapsedTime(&time); + + WriteMsg::write(WriteMsg::mlNormal, "\n"); + WriteMsg::write(CMSG_STATISTICS); + WriteMsg::write(CMSG_DETECTING_TIME, time); + WriteMsg::write(CMSG_PEAK_MEMORY_USAGE, config.stat.memory_peak / (1024 * 1024)); + + MAIN_END + return exit_code; +} diff --git a/cl/DuplicatedCodeFinder/inc/AbstractFilter.h b/cl/DuplicatedCodeFinder/inc/AbstractFilter.h index 6743a1a..588fa5f 100644 --- a/cl/DuplicatedCodeFinder/inc/AbstractFilter.h +++ b/cl/DuplicatedCodeFinder/inc/AbstractFilter.h @@ -28,7 +28,6 @@ namespace columbus { namespace dcf { class AbstractFilter { private: - int maxValue; int currentValue; public: diff --git a/cl/DuplicatedCodeFinder/inc/Visitors/CSharpNamedVisitor.h b/cl/DuplicatedCodeFinder/inc/Visitors/CSharpNamedVisitor.h index c430383..c0c5fc7 100644 --- a/cl/DuplicatedCodeFinder/inc/Visitors/CSharpNamedVisitor.h +++ b/cl/DuplicatedCodeFinder/inc/Visitors/CSharpNamedVisitor.h @@ -83,7 +83,7 @@ class CSharpNamedVisitor : public NamedVisitor { if (!node.getAccessorCallIsEmpty()){ columbus::LANGUAGE_NAMESPACE::ListIterator it = node.getAccessorCallListIteratorBegin(); while (it != node.getAccessorCallListIteratorEnd()) { - if (&(*it) && (*it).getPosition().getFileNameKey() != 0) { + if (it->getPosition().getFileNameKey() != 0) { repr += std::string("(") + (*it).getIdentifier(); } ++it; @@ -98,7 +98,7 @@ class CSharpNamedVisitor : public NamedVisitor { if (!node.getAccessorCallIsEmpty()){ columbus::LANGUAGE_NAMESPACE::ListIterator it = node.getAccessorCallListIteratorBegin(); while (it != node.getAccessorCallListIteratorEnd()) { - if (&(*it) && (*it).getPosition().getFileNameKey() != 0) { + if (it->getPosition().getFileNameKey() != 0) { repr += std::string(")"); } ++it; @@ -176,7 +176,7 @@ class CSharpNamedVisitor : public NamedVisitor { if (!node.getAccessorCallIsEmpty()) { columbus::LANGUAGE_NAMESPACE::ListIterator it = node.getAccessorCallListIteratorBegin(); while (it != node.getAccessorCallListIteratorEnd()) { - if (&(*it) && (*it).getPosition().getFileNameKey() != 0) { + if (it->getPosition().getFileNameKey() != 0) { repr += std::string("(") + (*it).getIdentifier(); } ++it; @@ -199,7 +199,7 @@ class CSharpNamedVisitor : public NamedVisitor { if (!node.getAccessorCallIsEmpty()) { columbus::LANGUAGE_NAMESPACE::ListIterator it = node.getAccessorCallListIteratorBegin(); while (it != node.getAccessorCallListIteratorEnd()) { - if (&(*it) && (*it).getPosition().getFileNameKey() != 0) { + if (it->getPosition().getFileNameKey() != 0) { repr += std::string(")"); } ++it; diff --git a/cl/DuplicatedCodeFinder/inc/Visitors/CloneVisitorBase.h b/cl/DuplicatedCodeFinder/inc/Visitors/CloneVisitorBase.h index 5281916..185c02e 100644 --- a/cl/DuplicatedCodeFinder/inc/Visitors/CloneVisitorBase.h +++ b/cl/DuplicatedCodeFinder/inc/Visitors/CloneVisitorBase.h @@ -134,7 +134,6 @@ class CloneVisitorBase : public columbus::LANGUAGE_NAMESPACE::VisitorAbstractNo columbus::LimOrigin& limOrigin; std::vector& resultSequence; std::vector& nodeIdSequence; - int inside; bool analizeNode; std::set block_paths; std::ostream* out; diff --git a/cl/DuplicatedCodeFinder/inc/dcm.h b/cl/DuplicatedCodeFinder/inc/dcm.h index 38e2a77..a1377c8 100644 --- a/cl/DuplicatedCodeFinder/inc/dcm.h +++ b/cl/DuplicatedCodeFinder/inc/dcm.h @@ -112,13 +112,13 @@ class DuplicatedCodeMiner { * \brief destructor */ virtual ~DuplicatedCodeMiner(); - + int getCloneClassNum() const; int getCloneInstanceNum()const; void saveGenealogy(); void setStatementFilter(bool val); - + int getNodeKindSequenceSize(); protected: @@ -140,7 +140,7 @@ class DuplicatedCodeMiner { std::map serializedAsgNodeNumberByComponenet; LimOrigin limOrigin; - + std::map > limNodeClineInstanceMap; std::map > limComponentClineInstanceMap; @@ -169,7 +169,7 @@ class DuplicatedCodeMiner { //v2 vector which contains the sequence of nodeIds together with the depth information std::vector nodeIdSequence; - + // map for the node and its connected nodes with NDCs NodeEmbeddednessVisitorBase::ConectedEdgesMap conectedEdgesMap; @@ -184,21 +184,21 @@ class DuplicatedCodeMiner { unsigned startPosition; Interval I; PotentialCloneInstance(unsigned startPosition, Interval I) : startPosition(startPosition), I(I) { } - + bool operator<(const PotentialCloneInstance& pci) const { return startPosition + I.a < pci.startPosition + pci.I.a; } - + PotentialCloneInstance(const PotentialCloneInstance& pci) : startPosition(pci.startPosition), I(pci.I) { } private: const PotentialCloneInstance& operator=(const PotentialCloneInstance& pci); // Intentionally not implemented! }; - + // maps a clone class to the set of its potential clone instances typedef std::map > CloneClassPotentialCloneInstanceMap; - + // the map of genealogy CloneInstance location for asg std::map serializedAsgMap; @@ -476,19 +476,6 @@ class DuplicatedCodeMiner { */ int serializeAsg(bool createComponent); - /** - * \internal - * \brief serialize the given asg. - * (This is used by the getInstanceIds to find the old instance of clones.) - * \param factory the asg factory which needs to be serialized - * \param componentLimId the id of the component. - * \param nodeKindSequence the vectors to fill - * \param nodeIdSequence the vectors to fill - * \param decDepthSign - * \param limFact - */ - void serializeAsg(Factory& factory, NodeId componentLimId, std::vector& nodeKindSequence, std::vector& nodeIdSequence, int& decDepthSign, columbus::lim::asg::Factory* limFact); - /** * \internal */ @@ -497,7 +484,7 @@ class DuplicatedCodeMiner { void fillPositionnodesVektor(LANGUAGE_NAMESPACE::Factory &rCurFact, std::vector &sortedPostitionNodes, const std::string& componenetId); bool isNodeAfter(const LANGUAGE_NAMESPACE::BASE_NAMESPACE::Positioned &reference, const LANGUAGE_NAMESPACE::BASE_NAMESPACE::Positioned &questionNode); - + bool PutBeginSignToNode( std::stack &nodeStack, const LANGUAGE_NAMESPACE::BASE_NAMESPACE::Positioned* node, LANGUAGE_NAMESPACE::VisitorAbstractNodes* cloneVisitor); void PutEndSignToNode( std::stack &nodeStack,LANGUAGE_NAMESPACE::VisitorAbstractNodes* cloneVisitor ); @@ -539,19 +526,19 @@ class DuplicatedCodeMiner { * \internal * \brief compute the F1, ..., F6 atrtibutes on which the similarity is rested. */ - + void computeSimilarityAttributes(columbus::genealogy::CloneInstance& ci); enum F_attributes { F1 = 1, F2, F3, F4, F5, F6 }; - const std::string& getFString(F_attributes F, const columbus::genealogy::CloneInstance& ci) { + const std::string* getFString(F_attributes F, const columbus::genealogy::CloneInstance& ci) { switch (F) { - case F1: return ci.getPath(); - case F2: return NULL; - case F3: return ci.getF3_HeadNodeUniqueName(); - case F4: return ci.getF4_AncestorUniqueName(); - case F5: return ci.getF4_AncestorUniqueName(); - case F6: return ci.getF6_LexicalStructure(); - default: return NULL; + case F1: return &ci.getPath(); + case F2: return nullptr; + case F3: return &ci.getF3_HeadNodeUniqueName(); + case F4: return &ci.getF4_AncestorUniqueName(); + case F5: return &ci.getF4_AncestorUniqueName(); + case F6: return &ci.getF6_LexicalStructure(); + default: return nullptr; } } double getStringSimilarity(std::string& s1, std::string& s2, double& dist, double* alpha, unsigned int limit); @@ -586,7 +573,7 @@ class DuplicatedCodeMiner { NodeId getLimComponenetIdByName(const std::string& name, const columbus::lim::asg::Factory& factory); const std::string& getAsgNameByLimId(columbus::NodeId limId, const columbus::lim::asg::Factory& factory) const; - + /** * \internal * \brief get clone instances of 'system' @@ -596,7 +583,7 @@ class DuplicatedCodeMiner { #endif - + public: /** * \brief start duplicate code mining diff --git a/cl/DuplicatedCodeFinder/src/AbstractFilter.cpp b/cl/DuplicatedCodeFinder/src/AbstractFilter.cpp index 5d91b66..ac7fdab 100644 --- a/cl/DuplicatedCodeFinder/src/AbstractFilter.cpp +++ b/cl/DuplicatedCodeFinder/src/AbstractFilter.cpp @@ -21,7 +21,7 @@ #include "../inc/common.h" -AbstractFilter::AbstractFilter() :maxValue(0), currentValue(0){ +AbstractFilter::AbstractFilter() : currentValue(0){ } int AbstractFilter::getMaxValue() { diff --git a/cl/DuplicatedCodeFinder/src/CloneVisitorBase.cpp b/cl/DuplicatedCodeFinder/src/CloneVisitorBase.cpp index 2583ae4..540bd96 100644 --- a/cl/DuplicatedCodeFinder/src/CloneVisitorBase.cpp +++ b/cl/DuplicatedCodeFinder/src/CloneVisitorBase.cpp @@ -27,7 +27,7 @@ using namespace common; CloneVisitorBase::CloneVisitorBase( std::set& visitedLines , std::set& visitedLimNodes - , columbus::LimOrigin& limOrigin + , columbus::LimOrigin& limOrigin , std::vector& _resultSequence , std::vector& _nodeIdSequence , CloneKind _ck /*= schemaOnly*/ @@ -49,7 +49,6 @@ CloneVisitorBase::CloneVisitorBase( , limOrigin(limOrigin) , resultSequence(_resultSequence) , nodeIdSequence(_nodeIdSequence) - , inside(0) , analizeNode(_analizeNode) , block_paths() , out(NULL) @@ -88,7 +87,9 @@ bool CloneVisitorBase::isAnalizeNode(const Base& node) { int CloneVisitorBase::getSeparator() { --separatorCounter; - CHECK_SEPARATOR(separatorCounter); + #ifndef NDEBUG + CHECK_SEPARATOR(separatorCounter); + #endif return separatorCounter; } @@ -133,14 +134,12 @@ void CloneVisitorBase::addPattern(const Base& n) { int kind = n.getNodeKind(); if (analizeNode && isAnalizeNode(n)) - inside++; - - if (inside == 0 && analizeNode) - addToResultSequence(getSeparator()); - else { - addToResultSequence((int)kind); + { + addBeginEndSeparator(); } + addToResultSequence((int)kind); + //it must be a positioned.....checked before addPattern is called addToNodeIdSequence(dynamic_cast(&n)); } @@ -149,32 +148,23 @@ void CloneVisitorBase::decreaseDepth(const Base& n) { addToResultSequence(decDepthSign); addToNodeIdSequence(NULL); - - if (analizeNode && isAnalizeNode(n)) { - if (inside>0) { - inside--; - if (inside == 0) { - addBeginEndSeparator(); - } - } - } } void CloneVisitorBase::addFileSeparator() { - + addToResultSequence(/*globalFileSeparator*/getSeparator()); - addToNodeIdSequence(NULL); + addToNodeIdSequence(NULL); } void CloneVisitorBase::addBeginEndSeparator() { - + addToResultSequence(/*beginEndSeparator*/getSeparator()); addToNodeIdSequence(NULL); } void CloneVisitorBase::blockNode(const Base& b) { - - if (!AlgorithmCommon::getIsPositioned(b)) + + if (!AlgorithmCommon::getIsPositioned(b)) return; const Positioned& pos= dynamic_cast(b); /** @@ -227,13 +217,13 @@ void CloneVisitorBase::blockNode(const Base& b) { if (visitedLines.count(LineIdentifier(limFactory->getStringTable().get(lPath),line))!=0) { blockNodeKind = BK_asgNodeBlock; - blockedNode = b.getId(); - + blockedNode = b.getId(); + common::WriteMsg::write(common::WriteMsg::mlDDebug,"\nThe %s %d has already been visited.\n", lPath.c_str(),line); return; } } - + if (!currentLimNode.empty() && (visitedLimNodes.count(currentLimNode.top()) > 0)) { columbus::NodeId posibelBlockedNode = currentLimNode.top(); @@ -241,18 +231,18 @@ void CloneVisitorBase::blockNode(const Base& b) { blockNodeKind = BK_limNodeBlock; blockedNode = posibelBlockedNode; common::WriteMsg::write(common::WriteMsg::mlDDebug,"The lim node %s %s %d already visited java %d",lim::asg::Common::toString(limFactory->getRef(blockedNode ).getNodeKind()).c_str(),lPath.c_str(),line,b.getId()); - + } - return; + return; } - + for (std::set::iterator s_iter=block_paths.begin();s_iter!=block_paths.end();++s_iter) { std::string b_path=(*s_iter); if (lPath.find(b_path)!=std::string::npos) { common::WriteMsg::write(CMSG_FILTERED_OUT, lPath.c_str()); blockNodeKind = BK_file; - blockedNode = 0; + blockedNode = 0; return; } } @@ -273,18 +263,18 @@ void CloneVisitorBase::setOutputStream(std::ostream& out) { this->out = &out; } -void CloneVisitorBase::incDepth() { - depth++; +void CloneVisitorBase::incDepth() { + depth++; } -void CloneVisitorBase::decDepth() { - depth--; +void CloneVisitorBase::decDepth() { + depth--; } void CloneVisitorBase::setFactory( columbus::LANGUAGE_NAMESPACE::Factory* _factory, columbus::NodeId currentLimComponentId) { factory = _factory; currentLimComponent = currentLimComponentId; - lastIsFilteredOut = false; + lastIsFilteredOut = false; } int CloneVisitorBase::getUniqueValue() { @@ -299,7 +289,7 @@ int CloneVisitorBase::getBeginEndSeparator() { return 0; } -bool CloneVisitorBase::isSepCharacter(int s) { +bool CloneVisitorBase::isSepCharacter(int s) { return (s>INT_MIN+separatorCounter && s!=decDepthSign); } @@ -307,8 +297,8 @@ bool CloneVisitorBase::isSepDecDepthSign(int s) { return (s==decDepthSign); } -int CloneVisitorBase::getDecDepthSign() { - return decDepthSign; +int CloneVisitorBase::getDecDepthSign() { + return decDepthSign; } void CloneVisitorBase::addBlockPath(const std::string& path) { @@ -408,7 +398,7 @@ void CloneVisitorBase::visit(const Positioned& n,bool callVirtualParent){ } else { //not considering non-positioned nodes except in python where the packages nodes are not Positioned nodes #ifdef SCHEMA_CSHARP - if (n.getNodeKind() != columbus::LANGUAGE_NAMESPACE::ndkNamespaceDeclarationSyntax) + if (n.getNodeKind() != columbus::LANGUAGE_NAMESPACE::ndkNamespaceDeclarationSyntax) #endif return; } @@ -437,8 +427,8 @@ void CloneVisitorBase::visitEnd(const Positioned& n, bool callVirtualParent) { } evoluteLimNode(n,true); - - + + if (blockNodeKind != BK_none) return; @@ -488,7 +478,7 @@ bool CloneVisitorBase::evoluteLimNode( const Base& n ,bool end){ return true; } } else if (currentLimNode.empty()) { - currentLimNode.push(limFactory->getRoot()->getId()); + currentLimNode.push(limFactory->getRoot()->getId()); } return false; } @@ -505,7 +495,7 @@ bool CloneVisitorBase::parseLimNodeId( const Base& n, columbus::NodeId& limNodeI void CloneVisitorBase::assignSrcFileToComponenet( std::string &lPath ,columbus::NodeId currentLimComponent) { (*fileNamesByComponent)[currentLimComponent].insert(limFactory->getStringTable().set(lPath.c_str())); - for ( columbus::lim::asg::ListIterator + for ( columbus::lim::asg::ListIterator it = limFactory->getReverseEdges().constIteratorBegin(currentLimComponent,columbus::lim::asg::edkComponent_Contains); it != limFactory->getReverseEdges().constIteratorEnd(currentLimComponent,columbus::lim::asg::edkComponent_Contains); ++it) { diff --git a/cl/DuplicatedCodeFinder/src/dcm.cpp b/cl/DuplicatedCodeFinder/src/dcm.cpp index fb91e71..b569694 100644 --- a/cl/DuplicatedCodeFinder/src/dcm.cpp +++ b/cl/DuplicatedCodeFinder/src/dcm.cpp @@ -178,7 +178,7 @@ namespace columbus { columbus::genealogy::Component* component = ci.getComponent(); if (component == NULL) throw Exception(COLUMBUS_LOCATION, CMSG_EX_MISSING_COMPONENT_FOR_CI); - + Factory* factory = currentFactory.operator ()(component->getLocation()); // For computing F1, F2, F3, F4, F5 only the first subtree is used! @@ -193,7 +193,7 @@ namespace columbus { F5: The relative position of the code segment inside its first named ancestor. F6: Lexical structure of the clone instance. */ - + // ============================ Computing F1 Attribute ========================================= // The path (F1) is always stored // ============================ Computing F2 Attribute ========================================= @@ -295,7 +295,7 @@ namespace columbus { } } - + double DuplicatedCodeMiner::similarity(const columbus::genealogy::CloneInstance& from, const columbus::genealogy::CloneInstance& to) { static unsigned long counter = 0; double inf=std::numeric_limits::infinity(); @@ -559,7 +559,6 @@ namespace columbus { ProcessPatternFilter() : sequence(NULL) , min_inst_length(0) - , filteredNodes(NULL) , dcm(NULL) { @@ -571,7 +570,7 @@ namespace columbus { unsigned min_inst_length; - std::map >* filteredNodes; + std::set filteredNodeIndexes; DuplicatedCodeMiner *dcm; public: @@ -595,12 +594,9 @@ namespace columbus { } else { if(drop_end !=0 && ( (drop_end - drop_begin) >= min_inst_length ) ) { // drop node at x position - for(unsigned i = drop_begin; i < drop_end; i++) { - ClonePositioned* clonePos = dcm->nodeIdSequence[i]; - if(clonePos != NULL) { - (*filteredNodes)[dcm->getAsgNameByLimId(clonePos->getLimComponentId(), *dcm->limFact)].insert(clonePos->getId()); - } - } + for(unsigned i = drop_begin; i < drop_end; i++) + filteredNodeIndexes.insert(i); + } drop_begin = 0; drop_end = 0; @@ -610,12 +606,8 @@ namespace columbus { if(drop_end !=0 && ( (drop_end - drop_begin) >= min_inst_length ) ) { // drop node at x position - for(unsigned i = drop_begin; i < drop_end; i++) { - ClonePositioned* clonePos = dcm->nodeIdSequence[i]; - if(clonePos != NULL) { - (*filteredNodes)[dcm->getAsgNameByLimId(clonePos->getLimComponentId(), *dcm->limFact)].insert(clonePos->getId()); - } - } + for(unsigned i = drop_begin; i < drop_end; i++) + filteredNodeIndexes.insert(i); } } }; @@ -633,30 +625,35 @@ namespace columbus { ppf.sequence = &sequence; ppf.min_inst_length = config.patternMinFullLength; ppf.dcm = this; - ppf.filteredNodes = &filteredNodes; LinearSuffixArray suffixArray(sequence); LinearSuffixArray::Duplicateiterator lduplicateIterator = suffixArray.iterator(1, config.patternMaxSingleLength, config.patternMinFullLength, false); lduplicateIterator.run(ppf); - size_t count = 0; - for(std::map >::iterator it = filteredNodes.begin(); it != filteredNodes.end(); ++it) { - count+=it->second.size(); - } + size_t count = ppf.filteredNodeIndexes.size(); auto filterTime = common::getProcessUsedTime().user - time.user; common::WriteMsg::write(CMSG_NODE_FILTERED_OUT, count, filterTime); config.stat.filterTime += filterTime; - - - perfSectionHandler.addTimeStamp("reserialize"); - // re serialize the asg/ast with filter if(count > 0) - serializeAsg(false); - + { + // use unused nodekinds for pattern filtered nodes + int lastSeparator = *std::max_element(nodeKindSequence.begin(), nodeKindSequence.end()); + if (lastSeparator < 1000) + lastSeparator = 1000; + for (size_t i = 0; i < nodeKindSequence.size(); ++i) + { + if (ppf.filteredNodeIndexes.find(i) != ppf.filteredNodeIndexes.end()) + { + if (nodeKindSequence[i] > 0) + nodeKindSequence[i] = ++lastSeparator; + } + } + } + updateMemoryStat(); } @@ -665,19 +662,19 @@ namespace columbus { ofstream out; out.open(filename, ios::out | ios::trunc); - unsigned indent_size = 0; + int indent_size = 0; if(out.is_open()) { for(auto node : nodeIdSequence) { if(node) { - for(unsigned i = 0; i < indent_size; ++i){ + for(int i = 0; i < indent_size; ++i){ out << " "; } - out << node->getStringPath() << " : " << node->getLine() << ":" << node->getCol() << " | " << node->getEndLine() << ":" << node->getEndCol() << endl; + out << node->getId() << " " << LANGUAGE_NAMESPACE::Common::toString((LANGUAGE_NAMESPACE::NodeKind)node->getNodeKind()) << " " << node->getStringPath() << " : " << node->getLine() << ":" << node->getCol() << " | " << node->getEndLine() << ":" << node->getEndCol() << endl; indent_size += 2; - }else{ + } else { out << endl; indent_size -= 2; } @@ -692,17 +689,23 @@ namespace columbus { int indent_size = 0; if(out.is_open()) { - for(auto kind : nodeKindSequence) + for(size_t i = 0; i < nodeKindSequence.size(); ++i) { - if(kind == -2){ + int kind = nodeKindSequence[i]; + + if(kind == -2 && indent_size > 0 ){ indent_size -= 2; } for(int i = 0; i < indent_size; ++i){ out << " "; } - out << kind << endl; + auto nodeInfo = nodeIdSequence[i]; + if (!nodeInfo) + out << kind << endl; + else + out << kind << " " << nodeInfo->getId() << " " << LANGUAGE_NAMESPACE::Common::toString((LANGUAGE_NAMESPACE::NodeKind)nodeInfo->getNodeKind()) << " " << nodeInfo->getStringPath() << " : " << nodeInfo->getLine() << ":" << nodeInfo->getCol() << " | " << nodeInfo->getEndLine() << ":" << nodeInfo->getEndCol() << endl; - if(kind != -2) + if(kind > 0) indent_size += 2; } @@ -724,9 +727,8 @@ namespace columbus { common::WriteMsg::write(CMSG_DETECTING_CLONES); nodeKindSequence.push_back(theCloneVisitor->getUniqueValue()); - /** - * suffix array patch - */ + // Debug + // dumpNodeKindSequence("NodeKindSequence.txt"); time = common::getProcessUsedTime(); @@ -973,7 +975,7 @@ namespace columbus { graph.createDirectedEdge(classItem, theComponent, graphsupport::graphconstants::ETYPE_LIM_COMPONENT, true); } // set clone class metrics - if (!cc.getIsVirtual()){ + if (!cc.getIsVirtual()) { if (getIsNeeded("CLLOC")) { columbus::graphsupport::setMetricFloat(graph, classItem, "CLLOC", (float)cc.getClloc()); @@ -998,7 +1000,7 @@ namespace columbus { if (getIsNeeded("NCR")) { columbus::graphsupport::incMetricFloat(graph, classItem, "NCR", (float)cc.getNcrad()); } - + //CLLOC * CI * CCO * NCR * CS if (getIsNeeded("CR")) { columbus::graphsupport::setMetricFloat(graph, classItem, "CR", (float)cc.getRisk()); @@ -1221,7 +1223,7 @@ namespace columbus { columbus::graphsupport::setMetricFloat(graph, gNode, "CLLC", (float)numCoveredLogicalLines/numLogicalLines); } - + if (getIsNeeded("LLDC")){ columbus::graphsupport::setMetricInt(graph, gNode, "LLDC", numCoveredLogicalLines); } @@ -1314,7 +1316,7 @@ namespace columbus { numLogicalLines++; } } - + std::vector itersection(max(coveredLines.size(),logicalLines.size())); std::vector::iterator retIterator; retIterator = std::set_intersection(coveredLines.begin(),coveredLines.end(),logicalLines.begin(),logicalLines.end(),itersection.begin()); @@ -1326,7 +1328,7 @@ namespace columbus { numCoveredLogicalLines++; } } - + if (getIsNeeded("CLLC")){ columbus::graphsupport::removeMetric(graph, gNode, "CLLC"); columbus::graphsupport::setMetricFloat(graph, gNode, "CLLC", (float)numCoveredLogicalLines/numLogicalLines); @@ -1348,12 +1350,11 @@ namespace columbus { time_lineMetrics += common::getProcessUsedTime().user - time_calculateLineMetrics.user; } - } + } } } //calculate CC and CCO metrics for clone instances and classes and set it on the genealogy. - for(genealogy::ListIterator cloneClassIt = currentSystem->getCloneClassesListIteratorBegin();cloneClassIt != currentSystem->getCloneClassesListIteratorEnd();++cloneClassIt) { columbus::genealogy::CloneClass& cc= (columbus::genealogy::CloneClass&) cloneClassIt->getFactory().getRef( cloneClassIt->getId()); if (cc.getIsVirtual()) @@ -1501,7 +1502,7 @@ namespace columbus { if (getIsNeeded("CLLOC")) { - cc.setClloc(((float)avgLocSum) / instances.size()); + cc.setClloc(((float)avgLocSum) / instances.size()/*avgLocNum*/); } // NCR, CE, CV, CR, CEE, CEG if (getIsNeeded("NCR")) { @@ -1661,23 +1662,6 @@ namespace columbus { return instanceRootIds; } - void DuplicatedCodeMiner::serializeAsg(Factory& factory, NodeId componentLimId, std::vector& nodeKindSequence, std::vector& nodeIdSequence, int& decDepthSign, columbus::lim::asg::Factory* _limFact) { - - CloneVisitorBase* cloneVisitor = new CloneVisitorBase(visitedLines, visitedLimNodes,limOrigin ,nodeKindSequence, nodeIdSequence, CloneVisitorBase::schemaOnly, config.ofc, false, _limFact); - - cloneVisitor->setFactory(&factory, componentLimId); - // factory.turnFilterOff(); // the lim filter is the valid. - WriteMsg::write(CMSG_LOAD_ASG_DONE); - updateMemoryStat(); - nodeKindSequence.clear(); - clearNodeIdSequence(nodeIdSequence); - - traversalPosiotionedNodes(factory, cloneVisitor,""); - - decDepthSign = cloneVisitor->getDecDepthSign(); - delete cloneVisitor; - } - int DuplicatedCodeMiner::serializeAsg(bool createComponent) { auto perfSectionHandler = common::PerformanceLogger::getPerformanceLogger().startSection("serializeAsg()"); @@ -1769,7 +1753,6 @@ namespace columbus { } config.stat.asgSerializationTime += common::getProcessUsedTime().user - serializeTime.user; - return exit_code; } @@ -1793,7 +1776,7 @@ namespace columbus { return EXIT_FAILURE; } updateMemoryStat(); - + do { // first we need to reset the state of the objects below (in case that DCF is being executed for the second time) first=!first; @@ -1832,7 +1815,7 @@ namespace columbus { } while (maxCCSize && needToSkip.size()>0 && first); common::timestat time = common::getProcessUsedTime(); - + updateMemoryStat(); WriteMsg::write(CMSG_CONVERTING_TO_GRAPH); TOGRAPH::convertBaseGraph(*limFact, graph, true, true, /*components=*/ true, /*variants=*/ true); @@ -1871,7 +1854,7 @@ namespace columbus { updateMemoryStat(); WriteMsg::write(CMSG_BUILD_CE); - + for (std::list::iterator fileIter=config.files.begin();fileIter!=config.files.end();++fileIter) { std::string componenetID; currentFactory.loadComponent(*fileIter,false,NULL,&componenetID); @@ -2295,7 +2278,7 @@ namespace columbus { cloneInstanceNext->setEndCol(itm.getEndCol()); itm.addNext(cloneInstanceNext); - } + } } } @@ -2746,7 +2729,7 @@ namespace columbus { limNodeClineInstanceMap[ci.getId()].insert(nodePos->getLimNodeId()); limComponentClineInstanceMap[ci.getId()].insert(nodePos->getLimComponentId()); lastLimNodeID = nodePos->getLimNodeId(); - } + } } } @@ -3521,7 +3504,7 @@ namespace columbus { if (cp->getLimComponentId() == componenetId){ int cco = 0; COVERAGE_VISITOR coverageVisitor; - + for (int i = 0; i < length; ++i) { const ClonePositioned* position = getNode(sequencePos + i); if (position) { @@ -3532,7 +3515,7 @@ namespace columbus { } } ci.setCco(cco+1); - } + } } } } diff --git a/cl/ESLint2Graph/CMakeLists.txt b/cl/ESLint2Graph/CMakeLists.txt index 780eaf2..29c102a 100644 --- a/cl/ESLint2Graph/CMakeLists.txt +++ b/cl/ESLint2Graph/CMakeLists.txt @@ -17,4 +17,5 @@ add_executable(${PROGRAM_NAME} ${SOURCES}) add_dependencies(${PROGRAM_NAME} ${COLUMBUS_GLOBAL_DEPENDENCY}) target_link_libraries(${PROGRAM_NAME} lim2graph graphsupport lim graph rul common csi strtable io ${COMMON_EXTERNAL_LIBRARIES}) add_copy_next_to_the_binary_dependency(${PROGRAM_NAME} ESLint.rul) +add_copy_next_to_the_binary_dependency(${PROGRAM_NAME} TSLint.rul) set_visual_studio_project_folder(${PROGRAM_NAME} TRUE) diff --git a/cl/ESLint2Graph/TSLint.rul b/cl/ESLint2Graph/TSLint.rul new file mode 100644 index 0000000..b020a1d --- /dev/null +++ b/cl/ESLint2Graph/TSLint.rul @@ -0,0 +1,7701 @@ + + + + + TSLINT + + + + + + + + + + + + + true + true + summarized + + true + Possible Errors + These rules relate to possible syntax or logic errors in JavaScript code. + <p>These rules relate to possible syntax or logic errors in JavaScript code.</p> + + + + + + + + + true + true + summarized + + true + Best Practices + These are rules designed to prevent you from making mistakes. They either prescribe a better way of doing something or help you avoid footguns. + <p>These are rules designed to prevent you from making mistakes. They either prescribe a better way of doing something or help you avoid footguns.</p> + + + + + + + + + true + true + summarized + + true + Strict Mode + These rules relate to using strict mode. + <p>These rules relate to using strict mode.</p> + + + + + + + + + true + true + summarized + + true + Variables + These rules have to do with variable declarations. + <p>These rules have to do with variable declarations.</p> + + + + + + + + + true + true + summarized + + true + ECMAScript 6 + These rules are only relevant to ES6 environments. + <p>These rules are only relevant to ES6 environments.</p> + + + + + + + + + true + true + summarized + + true + Node.js and CommonJS + These rules are specific to JavaScript running on Node.js or using CommonJS in the browser. + <p>These rules are specific to JavaScript running on Node.js or using CommonJS in the browser.</p> + + + + + + + + + true + true + summarized + + true + Stylistic Issues + These rules are purely matters of style and are quite subjective. + <p>These rules are purely matters of style and are quite subjective.</p> + + + + + + + + + + + + + + + + + + + + true + true + summarized + + true + Stylistic Issues + These rules are purely matters of style and are quite subjective within TypeScript. + <p>These rules are purely matters of style and are quite subjective within TypeScript.</p> + + + + + + + + + true + true + summarized + + true + TS Variables + These rules have to do with variable declarations within TypeScript. + <p>These rules have to do with variable declarations within TypeScript.</p> + + + + + + + + + true + true + summarized + + true + TS Possible Errors + These rules relate to possible syntax or logic errors in TypeScript code. + <p>These rules relate to possible syntax or logic errors in TypeScript code.</p> + + + + + + + + + true + true + summarized + + true + TS Best Practices + These are rules designed to prevent you from making mistakes in TypeScript. They either prescribe a better way of doing something or help you avoid footguns. + <p>These are rules designed to prevent you from making mistakes in TypeScript. They either prescribe a better way of doing something or help you avoid footguns.</p> + + + + + + + + + + + + + + + + + + + false + false + for-direction + Possible Errors + + true + for-direction + A for loop with a stop condition that can never be reached, such as one with a counter that moves in the wrong direction, will run infinitely. While there are occasions when an infinite loop is intended, the convention is to construct such loops as while loops. More typically, an infinite for loop is a bug. + <p>A for loop with a stop condition that can never be reached, such as one with a counter that moves in the wrong direction, will run infinitely. While there are occasions when an infinite loop is intended, the convention is to construct such loops as while loops. More typically, an infinite for loop is a bug.</p> + + + + Major + + + + + + + + false + false + getter-return + Possible Errors + + true + getter-return + The get syntax binds an object property to a function that will be called when that property is looked up. Note that every getter is expected to return a value. This rule enforces that a return statement is present in property getters. + <p>The get syntax binds an object property to a function that will be called when that property is looked up. Note that every getter is expected to return a value. This rule enforces that a return statement is present in property getters.</p> + + + + Major + { "allowImplicit": true } + + + + + + + false + false + no-await-in-loop + Possible Errors + + true + no-await-in-loop + Performing an operation on each element of an iterable is a common task. However, performing an await as part of each operation is an indication that the program is not taking full advantage of the parallelization benefits of async/await. + <p>Performing an operation on each element of an iterable is a common task. However, performing an await as part of each operation is an indication that the program is not taking full advantage of the parallelization benefits of async/await.</p> + + + + Major + + + + + + + true + false + no-compare-neg-zero + Possible Errors + + true + no-compare-neg-zero + The rule should warn against code that tries to compare against -0, since that will not work as intended. That is, code like x === -0 will pass for both +0 and -0. The author probably intended Object.is(x, -0). + <p>The rule should warn against code that tries to compare against -0, since that will not work as intended. That is, code like x === -0 will pass for both +0 and -0. The author probably intended Object.is(x, -0).</p> + + + + Major + + + + + + + true + false + no-cond-assign + Possible Errors + + true + no-cond-assign + In conditional statements, it is very easy to mistype a comparison operator (such as ==) as an assignment operator (such as =). For example: There are valid reasons to use assignment operators in conditional statements. However, it can be difficult to tell whether a specific assignment was intentional. + <p>In conditional statements, it is very easy to mistype a comparison operator (such as ==) as an assignment operator (such as =). For example: There are valid reasons to use assignment operators in conditional statements. However, it can be difficult to tell whether a specific assignment was intentional.</p> + + + + Major + "except-parens" + + + + + + + true + false + no-console + Possible Errors + + true + no-console + In JavaScript that is designed to be executed in the browser, it's considered a best practice to avoid using methods on console. Such messages are considered to be for debugging purposes and therefore not suitable to ship to the client. In general, calls using console should be stripped before being pushed to production. + <p>In JavaScript that is designed to be executed in the browser, it’s considered a best practice to avoid using methods on console. Such messages are considered to be for debugging purposes and therefore not suitable to ship to the client. In general, calls using console should be stripped before being pushed to production.</p> + + + + Major + { "allow": ["warn", "error"] } + + + + + + + true + false + no-constant-condition + Possible Errors + + true + no-constant-condition + Comparing a literal expression in a condition is usually a typo or development trigger for a specific behavior. This pattern is most likely an error and should be avoided. + <p>Comparing a literal expression in a condition is usually a typo or development trigger for a specific behavior. This pattern is most likely an error and should be avoided.</p> + + + + Major + { "checkLoops": true } + + + + + + + true + false + no-control-regex + Possible Errors + + true + no-control-regex + Control characters are special, invisible characters in the ASCII range 0-31. These characters are rarely used in JavaScript strings so a regular expression containing these characters is most likely a mistake. + <p>Control characters are special, invisible characters in the ASCII range 0-31. These characters are rarely used in JavaScript strings so a regular expression containing these characters is most likely a mistake.</p> + + + + Major + + + + + + + true + false + no-debugger + Possible Errors + + true + no-debugger + The debugger statement is used to tell the executing JavaScript environment to stop execution and start up a debugger at the current point in the code. This has fallen out of favor as a good practice with the advent of modern debugging and development tools. Production code should definitely not contain debugger, as it will cause the browser to stop executing code and open an appropriate debugger. + <p>The debugger statement is used to tell the executing JavaScript environment to stop execution and start up a debugger at the current point in the code. This has fallen out of favor as a good practice with the advent of modern debugging and development tools. Production code should definitely not contain debugger, as it will cause the browser to stop executing code and open an appropriate debugger.</p> + + + + Major + + + + + + + true + false + no-dupe-args + Possible Errors + + true + no-dupe-args + If more than one parameter has the same name in a function definition, the last occurrence “shadows” the preceding occurrences. A duplicated name might be a typing error. + <p>If more than one parameter has the same name in a function definition, the last occurrence “shadows” the preceding occurrences. A duplicated name might be a typing error.</p> + + + + Major + + + + + + + true + false + no-dupe-keys + Possible Errors + + true + no-dupe-keys + Multiple properties with the same key in object literals can cause unexpected behavior in your application. + <p>Multiple properties with the same key in object literals can cause unexpected behavior in your application.</p> + + + + Major + + + + + + + true + false + no-duplicate-case + Possible Errors + + true + no-duplicate-case + A switch statements with duplicate case labels is normally an indication of a programmer error. In the following example the 3rd case label uses again the literal 1 that has already been used in the first case label. Most likely the case block was copied from above and it was forgotten to change the literal. + <p>A switch statements with duplicate case labels is normally an indication of a programmer error. In the following example the 3rd case label uses again the literal 1 that has already been used in the first case label. Most likely the case block was copied from above and it was forgotten to change the literal.</p> + + + + Major + + + + + + + true + false + no-empty + Possible Errors + + true + no-empty + Empty block statements, while not technically errors, usually occur due to refactoring that wasn’t completed. They can cause confusion when reading code. + <p>Empty block statements, while not technically errors, usually occur due to refactoring that wasn’t completed. They can cause confusion when reading code.</p> + + + + Major + { "allowEmptyCatch": true } + + + + + + + true + false + no-empty-character-class + Possible Errors + + true + no-empty-character-class + Empty character classes in regular expressions do not match anything and can result in code that may not work as intended. + <p>Empty character classes in regular expressions do not match anything and can result in code that may not work as intended.</p> + + + + Major + + + + + + + true + false + no-ex-assign + Possible Errors + + true + no-ex-assign + If a catch clause in a try statement accidentally (or purposely) assigns another value to the exception parameter, it impossible to refer to the error from that point on. Since there is no arguments object to offer alternative access to this data, assignment of the parameter is absolutely destructive. + <p>If a catch clause in a try statement accidentally (or purposely) assigns another value to the exception parameter, it impossible to refer to the error from that point on. Since there is no arguments object to offer alternative access to this data, assignment of the parameter is absolutely destructive.</p> + + + + Major + + + + + + + true + false + no-extra-boolean-cast + Possible Errors + + true + no-extra-boolean-cast + In contexts such as an if statement's test where the result of the expression will already be coerced to a Boolean, casting to a Boolean via double negation (!!) is unnecessary. For example, these if statements are equivalent: + <p>In contexts such as an if statement’s test where the result of the expression will already be coerced to a Boolean, casting to a Boolean via double negation (!!) is unnecessary. For example, these if statements are equivalent:</p> + + + + Major + + + + + + + false + false + no-extra-parens + Possible Errors + + true + no-extra-parens + This rule restricts the use of parentheses to only where they are necessary. It may be restricted to report only function expressions. + <p>This rule restricts the use of parentheses to only where they are necessary. It may be restricted to report only function expressions.</p> + + + + Major + "all" + + + + + + + false + false + no-extra-semi + Possible Errors + + true + no-extra-semi + Typing mistakes and misunderstandings about where semicolons are required can lead to semicolons that are unnecessary. While not technically an error, extra semicolons can cause confusion when reading code. + <p>Typing mistakes and misunderstandings about where semicolons are required can lead to semicolons that are unnecessary. While not technically an error, extra semicolons can cause confusion when reading code.</p> + + + + Major + + + + + + + true + false + no-func-assign + Possible Errors + + true + no-func-assign + JavaScript functions can be written as a FunctionDeclaration function foo() { ... } or as a FunctionExpression var foo = function() { ... };. While a JavaScript interpreter might tolerate it, overwriting/reassigning a function written as a FunctionDeclaration is often indicative of a mistake or issue. + <p>JavaScript functions can be written as a FunctionDeclaration function foo() { … } or as a FunctionExpression var foo = function() { … };. While a JavaScript interpreter might tolerate it, overwriting/reassigning a function written as a FunctionDeclaration is often indicative of a mistake or issue.</p> + + + + Major + + + + + + + true + false + no-inner-declarations + Possible Errors + + true + no-inner-declarations + In JavaScript, prior to ES6, a function declaration is only allowed in the first level of a program or the body of another function, though parsers sometimes erroneously accept them elsewhere. This only applies to function declarations; named or anonymous function expressions can occur anywhere an expression is permitted. A variable declaration is permitted anywhere a statement can go, even nested deeply inside other blocks. This is often undesirable due to variable hoisting, and moving declarations to the root of the program or function body can increase clarity. Note that block bindings (let, const) are not hoisted and therefore they are not affected by this rule. + <p>In JavaScript, prior to ES6, a function declaration is only allowed in the first level of a program or the body of another function, though parsers sometimes erroneously accept them elsewhere. This only applies to function declarations; named or anonymous function expressions can occur anywhere an expression is permitted. A variable declaration is permitted anywhere a statement can go, even nested deeply inside other blocks. This is often undesirable due to variable hoisting, and moving declarations to the root of the program or function body can increase clarity. Note that block bindings (let, const) are not hoisted and therefore they are not affected by this rule.</p> + + + + Major + "functions" + + + + + + + true + false + no-invalid-regexp + Possible Errors + + true + no-invalid-regexp + An invalid pattern in a regular expression literal is a SyntaxError when the code is parsed, but an invalid string in RegExp constructors throws a SyntaxError only when the code is executed. + <p>An invalid pattern in a regular expression literal is a SyntaxError when the code is parsed, but an invalid string in RegExp constructors throws a SyntaxError only when the code is executed.</p> + + + + Major + { "allowConstructorFlags": ["u", "y"] } + + + + + + + true + false + no-irregular-whitespace + Possible Errors + + true + no-irregular-whitespace + Invalid or irregular whitespace causes issues with ECMAScript 5 parsers and also makes code harder to debug in a similar nature to mixed tabs and spaces. Various whitespace characters can be inputted by programmers by mistake for example from copying or keyboard shortcuts. Pressing Alt + Space on OS X adds in a non breaking space character for example. Known issues these spaces cause: + <p>Invalid or irregular whitespace causes issues with ECMAScript 5 parsers and also makes code harder to debug in a similar nature to mixed tabs and spaces. Various whitespace characters can be inputted by programmers by mistake for example from copying or keyboard shortcuts. Pressing Alt + Space on OS X adds in a non breaking space character for example. Known issues these spaces cause:</p> + + + + Major + { "skipStrings": true } + + + + + + + true + false + no-obj-calls + Possible Errors + + true + no-obj-calls + ECMAScript provides several global objects that are intended to be used as-is. Some of these objects look as if they could be constructors due their capitalization (such as Math and JSON) but will throw an error if you try to execute them as functions. The ECMAScript 5 specification makes it clear that both Math and JSON cannot be invoked: + <p>ECMAScript provides several global objects that are intended to be used as-is. Some of these objects look as if they could be constructors due their capitalization (such as Math and JSON) but will throw an error if you try to execute them as functions. The ECMAScript 5 specification makes it clear that both Math and JSON cannot be invoked:</p> + + + + Major + + + + + + + false + false + no-prototype-builtins + Possible Errors + + true + no-prototype-builtins + In ECMAScript 5.1, Object.create was added, which enables the creation of objects with a specified [[Prototype]]. Object.create(null) is a common pattern used to create objects that will be used as a Map. This can lead to errors when it is assumed that objects will have properties from Object.prototype. This rule prevents calling Object.prototype methods directly from an object. + <p>In ECMAScript 5.1, Object.create was added, which enables the creation of objects with a specified [[Prototype]]. Object.create(null) is a common pattern used to create objects that will be used as a Map. This can lead to errors when it is assumed that objects will have properties from Object.prototype. This rule prevents calling Object.prototype methods directly from an object.</p> + + + + Major + + + + + + + true + false + no-regex-spaces + Possible Errors + + true + no-regex-spaces + Regular expressions can be very complex and difficult to understand, which is why it's important to keep them as simple as possible in order to avoid mistakes. One of the more error-prone things you can do with a regular expression is to use more than one space, such as: In this regular expression, it's very hard to tell how many spaces are intended to be matched. It's better to use only one space and then specify how many spaces are expected, such as: Now it is very clear that three spaces are expected to be matched. + <p>Regular expressions can be very complex and difficult to understand, which is why it’s important to keep them as simple as possible in order to avoid mistakes. One of the more error-prone things you can do with a regular expression is to use more than one space, such as: In this regular expression, it’s very hard to tell how many spaces are intended to be matched. It’s better to use only one space and then specify how many spaces are expected, such as: Now it is very clear that three spaces are expected to be matched.</p> + + + + Major + + + + + + + true + false + no-sparse-arrays + Possible Errors + + true + no-sparse-arrays + Sparse arrays contain empty slots, most frequently due to multiple commas being used in an array literal, such as: While the items array in this example has a length of 2, there are actually no values in items[0] or items[1]. The fact that the array literal is valid with only commas inside, coupled with the length being set and actual item values not being set, make sparse arrays confusing for many developers. Consider the following: In this example, the colors array has a length of 3. But did the developer intend for there to be an empty spot in the middle of the array? Or is it a typo? The confusion around sparse arrays defined in this manner is enough that it's recommended to avoid using them unless you are certain that they are useful in your code. + <p>Sparse arrays contain empty slots, most frequently due to multiple commas being used in an array literal, such as: While the items array in this example has a length of 2, there are actually no values in items[0] or items[1]. The fact that the array literal is valid with only commas inside, coupled with the length being set and actual item values not being set, make sparse arrays confusing for many developers. Consider the following: In this example, the colors array has a length of 3. But did the developer intend for there to be an empty spot in the middle of the array? Or is it a typo? The confusion around sparse arrays defined in this manner is enough that it’s recommended to avoid using them unless you are certain that they are useful in your code.</p> + + + + Major + + + + + + + false + false + no-template-curly-in-string + Possible Errors + + true + no-template-curly-in-string + ECMAScript 6 allows programmers to create strings containing variable or expressions using template literals, instead of string concatenation, by writing expressions like ${variable} between two backtick quotes (`). It can be easy to use the wrong quotes when wanting to use template literals, by writing "${variable}", and end up with the literal value "${variable}" instead of a string containing the value of the injected expressions. + <p>ECMAScript 6 allows programmers to create strings containing variable or expressions using template literals, instead of string concatenation, by writing expressions like ${variable} between two backtick quotes (`). It can be easy to use the wrong quotes when wanting to use template literals, by writing "${variable}", and end up with the literal value "${variable}" instead of a string containing the value of the injected expressions.</p> + + + + Major + + + + + + + true + false + no-unexpected-multiline + Possible Errors + + true + no-unexpected-multiline + Semicolons are optional in JavaScript, via a process called automatic semicolon insertion (ASI). See the documentation for semi for a fuller discussion of that feature. The rules for ASI are relatively straightforward: In short, as once described by Isaac Schlueter, a \n character always ends a statement (just like a semicolon) unless one of the following is true: This particular rule aims to spot scenarios where a newline looks like it is ending a statement, but is not. + <p>Semicolons are optional in JavaScript, via a process called automatic semicolon insertion (ASI). See the documentation for semi for a fuller discussion of that feature. The rules for ASI are relatively straightforward: In short, as once described by Isaac Schlueter, a character always ends a statement (just like a semicolon) unless one of the following is true: This particular rule aims to spot scenarios where a newline looks like it is ending a statement, but is not.</p> + + + + Major + + + + + + + true + false + no-unreachable + Possible Errors + + true + no-unreachable + Because the return, throw, break, and continue statements unconditionally exit a block of code, any statements after them cannot be executed. Unreachable statements are usually a mistake. + <p>Because the return, throw, break, and continue statements unconditionally exit a block of code, any statements after them cannot be executed. Unreachable statements are usually a mistake.</p> + + + + Major + + + + + + + true + false + no-unsafe-finally + Possible Errors + + true + no-unsafe-finally + JavaScript suspends the control flow statements of try and catch blocks until the execution of finally block finishes. So, when return, throw, break, or continue is used in finally, control flow statements inside try and catch are overwritten, which is considered as unexpected behavior. + <p>JavaScript suspends the control flow statements of try and catch blocks until the execution of finally block finishes. So, when return, throw, break, or continue is used in finally, control flow statements inside try and catch are overwritten, which is considered as unexpected behavior.</p> + + + + Major + + + + + + + true + false + no-unsafe-negation + Possible Errors + + true + no-unsafe-negation + Just as developers might type -a + b when they mean -(a + b) for the negative of a sum, they might type !key in object by mistake when they almost certainly mean !(key in object) to test that a key is not in an object. !obj instanceof Ctor is similar. + <p>Just as developers might type -a + b when they mean -(a + b) for the negative of a sum, they might type !key in object by mistake when they almost certainly mean !(key in object) to test that a key is not in an object. !obj instanceof Ctor is similar.</p> + + + + Major + + + + + + + true + false + use-isnan + Possible Errors + + true + use-isnan + In JavaScript, NaN is a special value of the Number type. It's used to represent any of the "not-a-number" values represented by the double-precision 64-bit format as specified by the IEEE Standard for Binary Floating-Point Arithmetic. NaN has the unique property of not being equal to anything, including itself. That is to say, that the condition NaN !== NaN evaluates to true. + <p>In JavaScript, NaN is a special value of the Number type. It’s used to represent any of the “not-a-number” values represented by the double-precision 64-bit format as specified by the IEEE Standard for Binary Floating-Point Arithmetic. NaN has the unique property of not being equal to anything, including itself. That is to say, that the condition NaN !== NaN evaluates to true.</p> + + + + Major + + + + + + + false + false + valid-jsdoc + Possible Errors + + true + valid-jsdoc + JSDoc is a JavaScript API documentation generator. It uses specially-formatted comments inside of code to generate API documentation automatically. For example, this is what a JSDoc comment looks like for a function: The JSDoc comments have a syntax all their own, and it is easy to mistakenly mistype a comment because comments aren't often checked for correctness in editors. Further, it's very easy for the function definition to get out of sync with the comments, making the comments a source of confusion and error. + <p>JSDoc is a JavaScript API documentation generator. It uses specially-formatted comments inside of code to generate API documentation automatically. For example, this is what a JSDoc comment looks like for a function: The JSDoc comments have a syntax all their own, and it is easy to mistakenly mistype a comment because comments aren’t often checked for correctness in editors. Further, it’s very easy for the function definition to get out of sync with the comments, making the comments a source of confusion and error.</p> + + + + Major + + { + "requireReturn": false + } + + + + + + + true + false + valid-typeof + Possible Errors + + true + valid-typeof + For a vast majority of use-cases, the only valid results of the typeof operator will be one of the following: "undefined", "object", "boolean", "number", "string", and "function". When the result of a typeof operation is compared against a string that is not one of these strings, it is usually a typo. This rule ensures that when the result of a typeof operation is compared against a string, that string is in the aforementioned set. + <p>For a vast majority of use-cases, the only valid results of the typeof operator will be one of the following: “undefined”, “object”, “boolean”, “number”, “string”, and “function”. When the result of a typeof operation is compared against a string that is not one of these strings, it is usually a typo. This rule ensures that when the result of a typeof operation is compared against a string, that string is in the aforementioned set.</p> + + + + Major + { "requireStringLiterals": true } + + + + + + + + + + + + + + + + + false + false + accessor-pairs + Best Practices + + true + accessor-pairs + It's a common mistake in JavaScript to create an object with just a setter for a property but never have a corresponding getter defined for it. Without a getter, you cannot read the property, so it ends up not being used. Here are some examples: This rule warns if setters are defined without getters. Using an option getWithoutSet, it will warn if you have a getter without a setter also. + <p>It’s a common mistake in JavaScript to create an object with just a setter for a property but never have a corresponding getter defined for it. Without a getter, you cannot read the property, so it ends up not being used. Here are some examples: This rule warns if setters are defined without getters. Using an option getWithoutSet, it will warn if you have a getter without a setter also.</p> + + + + Major + + { + "setWithoutGet": true, + "getWithoutSet": false + } + + + + + + + false + false + array-callback-return + Best Practices + + true + array-callback-return + Array has several methods for filtering, mapping, and folding. If we forget to write return statement in a callback of those, it’s probably a mistake. + <p>Array has several methods for filtering, mapping, and folding. If we forget to write return statement in a callback of those, it’s probably a mistake.</p> + + + + Major + + { + "allowImplicit": false + } + + + + + + + false + false + block-scoped-var + Best Practices + + true + block-scoped-var + The block-scoped-var rule generates warnings when variables are used outside of the block in which they were defined. This emulates C-style block scope. + <p>The block-scoped-var rule generates warnings when variables are used outside of the block in which they were defined. This emulates C-style block scope.</p> + + + + Major + + + + + + + false + false + class-methods-use-this + Best Practices + + true + class-methods-use-this + If a class method does not use this, it can sometimes be made into a static function. If you do convert the method into a static function, instances of the class that call that particular method have to be converted to a static call as well (MyClass.callStaticMethod()) + <p>If a class method does not use this, it can sometimes be made into a static function. If you do convert the method into a static function, instances of the class that call that particular method have to be converted to a static call as well (MyClass.callStaticMethod())</p> + + + + Major + + + + + + + false + false + complexity + Best Practices + + true + complexity + Cyclomatic complexity measures the number of linearly independent paths through a program's source code. This rule allows setting a cyclomatic complexity threshold. + <p>Cyclomatic complexity measures the number of linearly independent paths through a program’s source code. This rule allows setting a cyclomatic complexity threshold.</p> + + + + Major + { "max": 2 } + + + + + + + false + false + consistent-return + Best Practices + + true + consistent-return + One of the confusing aspects of JavaScript is that any function may or may not return a value at any point in time. When a function exits without any return statement executing, the function returns undefined. Similarly, calling return without specifying any value will cause the function to return undefined. Only when return is called with a value is there a change in the function's return value. Unlike statically-typed languages that will catch when a function doesn't return the type of data expected, JavaScript has no such checks, meaning that it's easy to make mistakes such as this: Here, one branch of the function returns true, a Boolean value, while the other exits without specifying any value (and so returns undefined). This may be an indicator of a coding error, especially if this pattern is found in larger functions. + <p>One of the confusing aspects of JavaScript is that any function may or may not return a value at any point in time. When a function exits without any return statement executing, the function returns undefined. Similarly, calling return without specifying any value will cause the function to return undefined. Only when return is called with a value is there a change in the function’s return value. Unlike statically-typed languages that will catch when a function doesn’t return the type of data expected, JavaScript has no such checks, meaning that it’s easy to make mistakes such as this: Here, one branch of the function returns true, a Boolean value, while the other exits without specifying any value (and so returns undefined). This may be an indicator of a coding error, especially if this pattern is found in larger functions.</p> + + + + Major + {"treatUndefinedAsUnspecified": false} + + + + + + + false + false + curly + Best Practices + + true + curly + JavaScript allows the omission of curly braces when a block contains only one statement. However, it is considered by many to be best practice to never omit curly braces around blocks, even when they are optional, because it can lead to bugs and reduces code clarity. So the following: Can be rewritten as: There are, however, some who prefer to only use braces when there is more than one statement to be executed. + <p>JavaScript allows the omission of curly braces when a block contains only one statement. However, it is considered by many to be best practice to never omit curly braces around blocks, even when they are optional, because it can lead to bugs and reduces code clarity. So the following: Can be rewritten as: There are, however, some who prefer to only use braces when there is more than one statement to be executed.</p> + + + + Major + "all" + + + + + + + false + false + default-case + Best Practices + + true + default-case + Some code conventions require that all switch statements have a default case, even if the default case is empty, such as: The thinking is that it's better to always explicitly state what the default behavior should be so that it's clear whether or not the developer forgot to include the default behavior by mistake. Other code conventions allow you to skip the default case so long as there is a comment indicating the omission is intentional, such as: Once again, the intent here is to show that the developer intended for there to be no default behavior. + <p>Some code conventions require that all switch statements have a default case, even if the default case is empty, such as: The thinking is that it’s better to always explicitly state what the default behavior should be so that it’s clear whether or not the developer forgot to include the default behavior by mistake. Other code conventions allow you to skip the default case so long as there is a comment indicating the omission is intentional, such as: Once again, the intent here is to show that the developer intended for there to be no default behavior.</p> + + + + Major + {"commentPattern":"/^no default$/i"} + + + + + + + false + false + dot-location + Best Practices + + true + dot-location + JavaScript allows you to place newlines before or after a dot in a member expression. Consistency in placing a newline before or after the dot can greatly increase readability. + <p>JavaScript allows you to place newlines before or after a dot in a member expression. Consistency in placing a newline before or after the dot can greatly increase readability.</p> + + + + Major + "object" + + + + + + + false + false + dot-notation + Best Practices + + true + dot-notation + In JavaScript, one can access properties using the dot notation (foo.bar) or square-bracket notation (foo["bar"]). However, the dot notation is often preferred because it is easier to read, less verbose, and works better with aggressive JavaScript minimizers. + <p>In JavaScript, one can access properties using the dot notation (foo.bar) or square-bracket notation (foo[“bar”]). However, the dot notation is often preferred because it is easier to read, less verbose, and works better with aggressive JavaScript minimizers.</p> + + + + Major + + { + "allowKeywords": true + } + + + + + + + + true + false + eqeqeq + Best Practices + + true + eqeqeq + It is considered good practice to use the type-safe equality operators === and !== instead of their regular counterparts == and !=. The reason for this is that == and != do type coercion which follows the rather obscure Abstract Equality Comparison Algorithm. For instance, the following statements are all considered true: If one of those occurs in an innocent-looking statement such as a == b the actual problem is very difficult to spot. + <p>It is considered good practice to use the type-safe equality operators === and !== instead of their regular counterparts == and !=. The reason for this is that == and != do type coercion which follows the rather obscure Abstract Equality Comparison Algorithm. For instance, the following statements are all considered true: If one of those occurs in an innocent-looking statement such as a == b the actual problem is very difficult to spot.</p> + + + + Major + "always" + + + + + + + false + false + guard-for-in + Best Practices + + true + guard-for-in + Looping over objects with a for in loop will include properties that are inherited through the prototype chain. This behavior can lead to unexpected items in your for loop. + <p>Looping over objects with a for in loop will include properties that are inherited through the prototype chain. This behavior can lead to unexpected items in your for loop.</p> + + + + Major + + + + + + + false + false + no-alert + Best Practices + + true + no-alert + JavaScripts' alert, confirm, and prompt functions are widely considered to be obtrusive as UI elements and should be replaced by a more appropriate custom UI implementation. Furthermore, alert is often used while debugging code, which should be removed before deployment to production. + <p>JavaScripts’ alert, confirm, and prompt functions are widely considered to be obtrusive as UI elements and should be replaced by a more appropriate custom UI implementation. Furthermore, alert is often used while debugging code, which should be removed before deployment to production.</p> + + + + Major + + + + + + + false + false + no-caller + Best Practices + + true + no-caller + The use of arguments.caller and arguments.callee make several code optimizations impossible. They have been deprecated in future versions of JavaScript and their use is forbidden in ECMAScript 5 while in strict mode. + <p>The use of arguments.caller and arguments.callee make several code optimizations impossible. They have been deprecated in future versions of JavaScript and their use is forbidden in ECMAScript 5 while in strict mode.</p> + + + + Major + + + + + + + true + false + no-case-declarations + Best Practices + + true + no-case-declarations + This rule disallows lexical declarations (let, const, function and class) in case/default clauses. The reason is that the lexical declaration is visible in the entire switch block but it only gets initialized when it is assigned, which will only happen if the case where it is defined is reached. To ensure that the lexical declaration only applies to the current case clause wrap your clauses in blocks. + <p>This rule disallows lexical declarations (let, const, function and class) in case/default clauses. The reason is that the lexical declaration is visible in the entire switch block but it only gets initialized when it is assigned, which will only happen if the case where it is defined is reached. To ensure that the lexical declaration only applies to the current case clause wrap your clauses in blocks.</p> + + + + Major + + + + + + + false + false + no-div-regex + Best Practices + + true + no-div-regex + Require regex literals to escape division operators. + <p>Require regex literals to escape division operators.</p> + + + + Major + + + + + + + false + false + no-else-return + Best Practices + + true + no-else-return + If an if block contains a return statement, the else block becomes unnecessary. Its contents can be placed outside of the block. + <p>If an if block contains a return statement, the else block becomes unnecessary. Its contents can be placed outside of the block.</p> + + + + Major + {"allowElseIf": true} + + + + + + + false + false + no-empty-function + Best Practices + + true + no-empty-function + Empty functions can reduce readability because readers need to guess whether it’s intentional or not. So writing a clear comment for empty functions is a good practice. + <p>Empty functions can reduce readability because readers need to guess whether it’s intentional or not. So writing a clear comment for empty functions is a good practice.</p> + + + + Major + {"allow": []} + + + + + + + true + false + no-empty-pattern + Best Practices + + true + no-empty-pattern + When using destructuring, it's possible to create a pattern that has no effect. This happens when empty curly braces are used to the right of an embedded object destructuring pattern, such as: In this code, no new variables are created because a is just a location helper while the {} is expected to contain the variables to create, such as: In many cases, the empty object pattern is a mistake where the author intended to use a default value instead, such as: The difference between these two patterns is subtle, especially because the problematic empty pattern looks just like an object literal. + <p>When using destructuring, it’s possible to create a pattern that has no effect. This happens when empty curly braces are used to the right of an embedded object destructuring pattern, such as: In this code, no new variables are created because a is just a location helper while the {} is expected to contain the variables to create, such as: In many cases, the empty object pattern is a mistake where the author intended to use a default value instead, such as: The difference between these two patterns is subtle, especially because the problematic empty pattern looks just like an object literal.</p> + + + + Major + + + + + + + false + false + no-eq-null + Best Practices + + true + no-eq-null + Comparing to null without a type-checking operator (== or !=), can have unintended results as the comparison will evaluate to true when comparing to not just a null, but also an undefined value. + <p>Comparing to null without a type-checking operator (== or !=), can have unintended results as the comparison will evaluate to true when comparing to not just a null, but also an undefined value.</p> + + + + Major + + + + + + + false + false + no-eval + Best Practices + + true + no-eval + JavaScript's eval() function is potentially dangerous and is often misused. Using eval() on untrusted code can open a program up to several different injection attacks. The use of eval() in most contexts can be substituted for a better, alternative approach to a problem. + <p>JavaScript’s eval() function is potentially dangerous and is often misused. Using eval() on untrusted code can open a program up to several different injection attacks. The use of eval() in most contexts can be substituted for a better, alternative approach to a problem.</p> + + + + Major + {"allowIndirect": true} + + + + + + + false + false + no-extend-native + Best Practices + + true + no-extend-native + In JavaScript, you can extend any object, including builtin or "native" objects. Sometimes people change the behavior of these native objects in ways that break the assumptions made about them in other parts of the code. For example here we are overriding a builtin method that will then affect all Objects, even other builtins. A common suggestion to avoid this problem would be to wrap the inside of the for loop with users.hasOwnProperty(id). However, if this rule is strictly enforced throughout your codebase you won't need to take that step. + <p>In JavaScript, you can extend any object, including builtin or “native” objects. Sometimes people change the behavior of these native objects in ways that break the assumptions made about them in other parts of the code. For example here we are overriding a builtin method that will then affect all Objects, even other builtins. A common suggestion to avoid this problem would be to wrap the inside of the for loop with users.hasOwnProperty(id). However, if this rule is strictly enforced throughout your codebase you won’t need to take that step.</p> + + + + Major + {"exceptions": []} + + + + + + + false + false + no-extra-bind + Best Practices + + true + no-extra-bind + The bind() method is used to create functions with specific this values and, optionally, binds arguments to specific values. When used to specify the value of this, it's important that the function actually use this in its function body. For example: This code is an example of a good use of bind() for setting the value of this. Sometimes during the course of code maintenance, the this value is removed from the function body. In that case, you can end up with a call to bind() that doesn't accomplish anything: In this code, the reference to this has been removed but bind() is still used. In this case, the bind() is unnecessary overhead (and a performance hit) and can be safely removed. + <p>The bind() method is used to create functions with specific this values and, optionally, binds arguments to specific values. When used to specify the value of this, it’s important that the function actually use this in its function body. For example: This code is an example of a good use of bind() for setting the value of this. Sometimes during the course of code maintenance, the this value is removed from the function body. In that case, you can end up with a call to bind() that doesn’t accomplish anything: In this code, the reference to this has been removed but bind() is still used. In this case, the bind() is unnecessary overhead (and a performance hit) and can be safely removed.</p> + + + + Major + + + + + + + false + false + no-extra-label + Best Practices + + true + no-extra-label + The --fix option on the command line can automatically fix some of the problems reported by this rule.If a loop contains no nested loops or switches, labeling the loop is unnecessary. + <p>The --fix option on the command line can automatically fix some of the problems reported by this rule.If a loop contains no nested loops or switches, labeling the loop is unnecessary.</p> + + + + Major + + + + + + + true + false + no-fallthrough + Best Practices + + true + no-fallthrough + The switch statement in JavaScript is one of the more error-prone constructs of the language thanks in part to the ability to "fall through" from one case to the next. For example: In this example, if foo is 1,then execution will flow through both cases, as the first falls through to the second. You can prevent this by using break, as in this example: That works fine when you don't want a fallthrough, but what if the fallthrough is intentional, there is no way to indicate that in the language. It's considered a best practice to always indicate when a fallthrough is intentional using a comment: In this example, there is no confusion as to the expected behavior. It is clear that the first case is meant to fall through to the second case. + <p>The switch statement in JavaScript is one of the more error-prone constructs of the language thanks in part to the ability to “fall through” from one case to the next. For example: In this example, if foo is 1,then execution will flow through both cases, as the first falls through to the second. You can prevent this by using break, as in this example: That works fine when you don’t want a fallthrough, but what if the fallthrough is intentional, there is no way to indicate that in the language. It’s considered a best practice to always indicate when a fallthrough is intentional using a comment: In this example, there is no confusion as to the expected behavior. It is clear that the first case is meant to fall through to the second case.</p> + + + + Major + { "commentPattern": "break[\\s\\w]*omitted" } + + + + + + + false + false + no-floating-decimal + Best Practices + + true + no-floating-decimal + Float values in JavaScript contain a decimal point, and there is no requirement that the decimal point be preceded or followed by a number. For example, the following are all valid JavaScript numbers: Although not a syntax error, this format for numbers can make it difficult to distinguish between true decimal numbers and the dot operator. For this reason, some recommend that you should always include a number before and after a decimal point to make it clear the intent is to create a decimal number. + <p>Float values in JavaScript contain a decimal point, and there is no requirement that the decimal point be preceded or followed by a number. For example, the following are all valid JavaScript numbers: Although not a syntax error, this format for numbers can make it difficult to distinguish between true decimal numbers and the dot operator. For this reason, some recommend that you should always include a number before and after a decimal point to make it clear the intent is to create a decimal number.</p> + + + + Major + + + + + + + true + false + no-global-assign + Best Practices + + true + no-global-assign + JavaScript environments contain a number of built-in global variables, such as window in browsers and process in Node.js. In almost all cases, you don’t want to assign a value to these global variables as doing so could result in losing access to important functionality. + <p>JavaScript environments contain a number of built-in global variables, such as window in browsers and process in Node.js. In almost all cases, you don’t want to assign a value to these global variables as doing so could result in losing access to important functionality. </p> + + + + Major + { "exceptions": ["Object"] } + + + + + + + false + false + no-implicit-coercion + Best Practices + + true + no-implicit-coercion + In JavaScript, there are a lot of different ways to convert value types. Some of them might be hard to read and understand. Such as: Those can be replaced with the following code: + <p>In JavaScript, there are a lot of different ways to convert value types. Some of them might be hard to read and understand. Such as: Those can be replaced with the following code:</p> + + + + Major + { + "boolean": true, + "number": true, + "string": true, + "allow": [] + } + + + + + + + false + false + no-implicit-globals + Best Practices + + true + no-implicit-globals + When working with browser scripts, developers often forget that variable and function declarations at the top-level scope become global variables on the window object. As opposed to modules which have their own scope. Globals should be explicitly assigned to window or self if that is the intent. Otherwise variables intended to be local to the script should be wrapped in an IIFE. + <p>When working with browser scripts, developers often forget that variable and function declarations at the top-level scope become global variables on the window object. As opposed to modules which have their own scope. Globals should be explicitly assigned to window or self if that is the intent. Otherwise variables intended to be local to the script should be wrapped in an IIFE.</p> + + + + Major + + + + + + + false + false + no-implied-eval + Best Practices + + true + no-implied-eval + It's considered a good practice to avoid using eval() in JavaScript. There are security and performance implications involved with doing so, which is why many linters (including ESLint) recommend disallowing eval(). However, there are some other ways to pass a string and have it interpreted as JavaScript code that have similar concerns. The first is using setTimeout(), setInterval() or execScript() (Internet Explorer only), both of which can accept a string of JavaScript code as their first argument. For example: This is considered an implied eval() because a string of JavaScript code is passed in to be interpreted. The same can be done with setInterval() and execScript(). Both interpret the JavaScript code in the global scope. For both setTimeout() and setInterval(), the first argument can also be a function, and that is considered safer and is more performant: The best practice is to always use a function for the first argument of setTimeout() and setInterval() (and avoid execScript()). + <p>It’s considered a good practice to avoid using eval() in JavaScript. There are security and performance implications involved with doing so, which is why many linters (including ESLint) recommend disallowing eval(). However, there are some other ways to pass a string and have it interpreted as JavaScript code that have similar concerns. The first is using setTimeout(), setInterval() or execScript() (Internet Explorer only), both of which can accept a string of JavaScript code as their first argument. For example: This is considered an implied eval() because a string of JavaScript code is passed in to be interpreted. The same can be done with setInterval() and execScript(). Both interpret the JavaScript code in the global scope. For both setTimeout() and setInterval(), the first argument can also be a function, and that is considered safer and is more performant: The best practice is to always use a function for the first argument of setTimeout() and setInterval() (and avoid execScript()).</p> + + + + Major + + + + + + + false + false + no-invalid-this + Best Practices + + true + no-invalid-this + Under the strict mode, this keywords outside of classes or class-like objects might be undefined and raise a TypeError. + <p>Under the strict mode, this keywords outside of classes or class-like objects might be undefined and raise a TypeError.</p> + + + + Major + + + + + + + true + false + no-iterator + Best Practices + + true + no-iterator + The __iterator__ property was a SpiderMonkey extension to JavaScript that could be used to create custom iterators that are compatible with JavaScript's for in and for each constructs. However, this property is now obsolete, so it should not be used. Here's an example of how this used to work: You should use ECMAScript 6 iterators and generators instead. + <p>The <strong>iterator</strong> property was a SpiderMonkey extension to JavaScript that could be used to create custom iterators that are compatible with JavaScript’s for in and for each constructs. However, this property is now obsolete, so it should not be used. Here’s an example of how this used to work: You should use ECMAScript 6 iterators and generators instead.</p> + + + + Major + + + + + + + false + false + no-labels + Best Practices + + true + no-labels + Labeled statements in JavaScript are used in conjunction with break and continue to control flow around multiple loops. For example: The break outer statement ensures that this code will not result in an infinite loop because control is returned to the next statement after the outer label was applied. If this statement was changed to be just break, control would flow back to the outer while statement and an infinite loop would result. While convenient in some cases, labels tend to be used only rarely and are frowned upon by some as a remedial form of flow control that is more error prone and harder to understand. + <p>Labeled statements in JavaScript are used in conjunction with break and continue to control flow around multiple loops. For example: The break outer statement ensures that this code will not result in an infinite loop because control is returned to the next statement after the outer label was applied. If this statement was changed to be just break, control would flow back to the outer while statement and an infinite loop would result. While convenient in some cases, labels tend to be used only rarely and are frowned upon by some as a remedial form of flow control that is more error prone and harder to understand.</p> + + + + Major + {"allowLoop": false, "allowSwitch": false} + + + + + + + false + false + no-lone-blocks + Best Practices + + true + no-lone-blocks + In JavaScript, prior to ES6, standalone code blocks delimited by curly braces do not create a new scope and have no use. For example, these curly braces do nothing to foo: In ES6, code blocks may create a new scope if a block-level binding (let and const), a class declaration or a function declaration (in strict mode) are present. A block is not considered redundant in these cases. + <p>In JavaScript, prior to ES6, standalone code blocks delimited by curly braces do not create a new scope and have no use. For example, these curly braces do nothing to foo: In ES6, code blocks may create a new scope if a block-level binding (let and const), a class declaration or a function declaration (in strict mode) are present. A block is not considered redundant in these cases.</p> + + + + Major + + + + + + + false + false + no-loop-func + Best Practices + + true + no-loop-func + Writing functions within loops tends to result in errors due to the way the function creates a closure around the loop. For example: In this case, you would expect each function created within the loop to return a different number. In reality, each function returns 10, because that was the last value of i in the scope. let or const mitigate this problem. In this case, each function created within the loop returns a different number as expected. + <p>Writing functions within loops tends to result in errors due to the way the function creates a closure around the loop. For example: In this case, you would expect each function created within the loop to return a different number. In reality, each function returns 10, because that was the last value of i in the scope. let or const mitigate this problem. In this case, each function created within the loop returns a different number as expected.</p> + + + + Major + + + + + + + false + false + no-magic-numbers + Best Practices + + true + no-magic-numbers + 'Magic numbers' are numbers that occur multiple time in code without an explicit meaning. They should preferably be replaced by named constants. + <p>‘Magic numbers’ are numbers that occur multiple time in code without an explicit meaning. They should preferably be replaced by named constants.</p> + + + + Major + { + "ignore": [], + "ignoreArrayIndexes": false, + "enforceConst": false, + "detectObjects": false + } + + + + + + + false + false + no-multi-spaces + Best Practices + + true + no-multi-spaces + Multiple spaces in a row that are not used for indentation are typically mistakes. For example: It's hard to tell, but there are two spaces between foo and ===. Multiple spaces such as this are generally frowned upon in favor of single spaces: Fixable: This rule is automatically fixable using the --fix flag on the command line. + <p>Multiple spaces in a row that are not used for indentation are typically mistakes. For example: It’s hard to tell, but there are two spaces between foo and ===. Multiple spaces such as this are generally frowned upon in favor of single spaces: Fixable: This rule is automatically fixable using the –fix flag on the command line.</p> + + + + Major + { + "ignoreEOLComments": false, + "exceptions": {} + } + + + + + + + false + false + no-multi-str + Best Practices + + true + no-multi-str + It's possible to create multiline strings in JavaScript by using a slash before a newline, such as: Some consider this to be a bad practice as it was an undocumented feature of JavaScript that was only formalized later. + <p>It’s possible to create multiline strings in JavaScript by using a slash before a newline, such as: Some consider this to be a bad practice as it was an undocumented feature of JavaScript that was only formalized later.</p> + + + + Major + + + + + + + false + false + no-new + Best Practices + + true + no-new + The goal of using new with a constructor is typically to create an object of a particular type and store that object in a variable, such as: It's less common to use new and not store the result, such as: In this case, the created object is thrown away because its reference isn't stored anywhere, and in many cases, this means that the constructor should be replaced with a function that doesn't require new to be used. + <p>The goal of using new with a constructor is typically to create an object of a particular type and store that object in a variable, such as: It’s less common to use new and not store the result, such as: In this case, the created object is thrown away because its reference isn’t stored anywhere, and in many cases, this means that the constructor should be replaced with a function that doesn’t require new to be used.</p> + + + + Major + + + + + + + false + false + no-new-func + Best Practices + + true + no-new-func + It's possible to create functions in JavaScript using the Function constructor, such as: This is considered by many to be a bad practice due to the difficult in debugging and reading these types of functions. + <p>It’s possible to create functions in JavaScript using the Function constructor, such as: This is considered by many to be a bad practice due to the difficult in debugging and reading these types of functions.</p> + + + + Major + + + + + + + true + false + no-new-wrappers + Best Practices + + true + no-new-wrappers + There are three primitive types in JavaScript that have wrapper objects: string, number, and boolean. These are represented by the constructors String, Number, and Boolean, respectively. The primitive wrapper types are used whenever one of these primitive values is read, providing them with object-like capabilities such as methods. Behind the scenes, an object of the associated wrapper type is created and then destroyed, which is why you can call methods on primitive values, such as: Behind the scenes in this example, a String object is constructed. The substring() method exists on String.prototype and so is accessible to the string instance. It's also possible to manually create a new wrapper instance: Although possible, there aren't any good reasons to use these primitive wrappers as constructors. They tend to confuse other developers more than anything else because they seem like they should act as primitives, but they do not. For example: The first problem is that primitive wrapper objects are, in fact, objects. That means typeof will return "object" instead of "string", "number", or "boolean". The second problem comes with boolean objects. Every object is truthy, that means an instance of Boolean always resolves to true even when its actual value is false. For these reasons, it's considered a best practice to avoid using primitive wrapper types with new. + <p>There are three primitive types in JavaScript that have wrapper objects: string, number, and boolean. These are represented by the constructors String, Number, and Boolean, respectively. The primitive wrapper types are used whenever one of these primitive values is read, providing them with object-like capabilities such as methods. Behind the scenes, an object of the associated wrapper type is created and then destroyed, which is why you can call methods on primitive values, such as: Behind the scenes in this example, a String object is constructed. The substring() method exists on String.prototype and so is accessible to the string instance. It’s also possible to manually create a new wrapper instance: Although possible, there aren’t any good reasons to use these primitive wrappers as constructors. They tend to confuse other developers more than anything else because they seem like they should act as primitives, but they do not. For example: The first problem is that primitive wrapper objects are, in fact, objects. That means typeof will return “object” instead of “string”, “number”, or “boolean”. The second problem comes with boolean objects. Every object is truthy, that means an instance of Boolean always resolves to true even when its actual value is false. For these reasons, it’s considered a best practice to avoid using primitive wrapper types with new.</p> + + + + Major + + + + + + + true + false + no-octal + Best Practices + + true + no-octal + Octal literals are numerals that begin with a leading zero, such as: The leading zero to identify an octal literal has been a source of confusion and error in JavaScript. ECMAScript 5 deprecates the use of octal numeric literals in JavaScript and octal literals cause syntax errors in strict mode. It's therefore recommended to avoid using octal literals in JavaScript code. + <p>Octal literals are numerals that begin with a leading zero, such as: The leading zero to identify an octal literal has been a source of confusion and error in JavaScript. ECMAScript 5 deprecates the use of octal numeric literals in JavaScript and octal literals cause syntax errors in strict mode. It’s therefore recommended to avoid using octal literals in JavaScript code.</p> + + + + Major + + + + + + + false + false + no-octal-escape + Best Practices + + true + no-octal-escape + As of version 5 of the ECMAScript specification, octal escape sequences are a deprecated feature and should not be used. It is recommended that Unicode escapes be used instead. + <p>As of version 5 of the ECMAScript specification, octal escape sequences are a deprecated feature and should not be used. It is recommended that Unicode escapes be used instead.</p> + + + + Major + + + + + + + false + false + no-param-reassign + Best Practices + + true + no-param-reassign + Assignment to variables declared as function parameters can be misleading and lead to confusing behavior, as modifying function parameters will also mutate the arguments object. Often, assignment to function parameters is unintended and indicative of a mistake or programmer error. + <p>Assignment to variables declared as function parameters can be misleading and lead to confusing behavior, as modifying function parameters will also mutate the arguments object. Often, assignment to function parameters is unintended and indicative of a mistake or programmer error.</p> + + + + Major + { + "props": false, + "ignorePropertyModificationsFor": [] + } + + + + + + + + false + false + no-proto + Best Practices + + true + no-proto + __proto__ property has been deprecated as of ECMAScript 3.1 and shouldn't be used in the code. Use getPrototypeOf method instead. + <p><strong>proto</strong> property has been deprecated as of ECMAScript 3.1 and shouldn’t be used in the code. Use getPrototypeOf method instead.</p> + + + + Major + + + + + + + false + false + no-redeclare + Best Practices + + true + no-redeclare + In JavaScript, it's possible to redeclare the same variable name using var. This can lead to confusion as to where the variable is actually declared and initialized. + <p>In JavaScript, it’s possible to redeclare the same variable name using var. This can lead to confusion as to where the variable is actually declared and initialized.</p> + + + + Major + { + "builtinGlobals": false + } + + + + + + + false + false + no-restricted-properties + Best Practices + + true + no-restricted-properties + Certain properties on objects may be disallowed in a codebase. This is useful for deprecating an API or restricting usage of a module’s methods. For example, you may want to disallow using describe.only when using Mocha or telling people to use Object.assign instead of _.extend. + <p>Certain properties on objects may be disallowed in a codebase. This is useful for deprecating an API or restricting usage of a module’s methods. For example, you may want to disallow using describe.only when using Mocha or telling people to use Object.assign instead of _.extend.</p> + + + + Major + + + + + + + + false + false + no-return-assign + Best Practices + + true + no-return-assign + One of the interesting, and sometimes confusing, aspects of JavaScript is that assignment can happen at almost any point. Because of this, an errant equals sign can end up causing assignment when the true intent was to do a comparison. This is especially true when using a return statement. For example: It is difficult to tell the intent of the return statement here. It's possible that the function is meant to return the result of bar + 2, but then why is it assigning to foo? It's also possible that the intent was to use a comparison operator such as == and that this code is an error. Because of this ambiguity, it's considered a best practice to not use assignment in return statements. + <p>One of the interesting, and sometimes confusing, aspects of JavaScript is that assignment can happen at almost any point. Because of this, an errant equals sign can end up causing assignment when the true intent was to do a comparison. This is especially true when using a return statement. For example: It is difficult to tell the intent of the return statement here. It’s possible that the function is meant to return the result of bar + 2, but then why is it assigning to foo? It’s also possible that the intent was to use a comparison operator such as == and that this code is an error. Because of this ambiguity, it’s considered a best practice to not use assignment in return statements.</p> + + + + Major + "always" + + + + + + + false + false + no-return-await + Best Practices + + true + no-return-await + Inside an async function, return await is useless. Since the return value of an async function is always wrapped in Promise.resolve, return await doesn’t actually do anything except add extra time before the overarching Promise resolves or rejects. This pattern is almost certainly due to programmer ignorance of the return semantics of async functions. + <p>Inside an async function, return await is useless. Since the return value of an async function is always wrapped in Promise.resolve, return await doesn’t actually do anything except add extra time before the overarching Promise resolves or rejects. This pattern is almost certainly due to programmer ignorance of the return semantics of async functions.</p> + + + + Major + + + + + + + false + false + no-script-url + Best Practices + + true + no-script-url + Using javascript: URLs is considered by some as a form of eval. Code passed in javascript: URLs has to be parsed and evaluated by the browser in the same way that eval is processed. + <p>Using javascript: URLs is considered by some as a form of eval. Code passed in javascript: URLs has to be parsed and evaluated by the browser in the same way that eval is processed.</p> + + + + Major + + + + + + + true + false + no-self-assign + Best Practices + + true + no-self-assign + Self assignments have no effect, so probably those are an error due to incomplete refactoring. Those indicate that what you should do is still remaining. + <p>Self assignments have no effect, so probably those are an error due to incomplete refactoring. Those indicate that what you should do is still remaining.</p> + + + + Major + {"props":false} + + + + + + + false + false + no-self-compare + Best Practices + + true + no-self-compare + Comparing a variable against itself is usually an error, either an typo or refactoring error. It is confusing to the reader and may potentially introduce a runtime error. The only time you would compare a variable against itself is when you are testing for NaN. However, it is far more appropriate to use typeof x === 'number' && isNaN(x) or the Number.isNaN ES2015 function for that use case rather than leaving the reader of the code to determine the intent of self comparison. + <p>Comparing a variable against itself is usually an error, either an typo or refactoring error. It is confusing to the reader and may potentially introduce a runtime error. The only time you would compare a variable against itself is when you are testing for NaN. However, it is far more appropriate to use typeof x === ‘number’ &amp;&amp; isNaN(x) or the Number.isNaN ES2015 function for that use case rather than leaving the reader of the code to determine the intent of self comparison.</p> + + + + Major + + + + + + + false + false + no-sequences + Best Practices + + true + no-sequences + The comma operator includes multiple expressions where only one is expected. It evaluates each operand from left to right and returns the value of the last operand. However, this frequently obscures side effects, and its use is often an accident. Here are some examples of its use: + <p>The comma operator includes multiple expressions where only one is expected. It evaluates each operand from left to right and returns the value of the last operand. However, this frequently obscures side effects, and its use is often an accident. Here are some examples of its use:</p> + + + + Major + + + + + + + false + false + no-throw-literal + Best Practices + + true + no-throw-literal + It is considered good practice to only throw the Error object itself or an object using the Error object as base objects for user-defined exceptions. The fundamental benefit of Error objects is that they automatically keep track of where they were built and originated. This rule restricts what can be thrown as an exception. When it was first created, it only prevented literals from being thrown (hence the name), but it has now been expanded to only allow expressions which have a possibility of being an Error object. + <p>It is considered good practice to only throw the Error object itself or an object using the Error object as base objects for user-defined exceptions. The fundamental benefit of Error objects is that they automatically keep track of where they were built and originated. This rule restricts what can be thrown as an exception. When it was first created, it only prevented literals from being thrown (hence the name), but it has now been expanded to only allow expressions which have a possibility of being an Error object.</p> + + + + Major + + + + + + + false + false + no-unmodified-loop-condition + Best Practices + + true + no-unmodified-loop-condition + Variables in a loop condition often are modified in the loop. If not, it’s possibly a mistake. + <p>Variables in a loop condition often are modified in the loop. If not, it’s possibly a mistake.</p> + + + + Major + + + + + + + false + false + no-unused-expressions + Best Practices + + true + no-unused-expressions + Unused expressions are those expressions that evaluate to a value but are never used. For example: This string is a valid JavaScript expression, but isn't actually used. Even though it's not a syntax error it is clearly a logic error and it has no effect on the code being executed. + <p>Unused expressions are those expressions that evaluate to a value but are never used. For example: This string is a valid JavaScript expression, but isn’t actually used. Even though it’s not a syntax error it is clearly a logic error and it has no effect on the code being executed.</p> + + + + Major + { + "allowShortCircuit": false, + "allowTernary": false, + "allowTaggedTemplates": false + } + + + + + + + true + false + no-unused-labels + Best Practices + + true + no-unused-labels + The --fix option on the command line can automatically fix some of the problems reported by this rule. Labels that are declared and not used anywhere in the code are most likely an error due to incomplete refactoring. + <p>The --fix option on the command line can automatically fix some of the problems reported by this rule. Labels that are declared and not used anywhere in the code are most likely an error due to incomplete refactoring.</p> + + + + Major + + + + + + + false + false + no-useless-call + Best Practices + + true + no-useless-call + The function invocation can be written by Function.prototype.call() and Function.prototype.apply(). But Function.prototype.call() and Function.prototype.apply() are slower than the normal function invocation. + <p>The function invocation can be written by Function.prototype.call() and Function.prototype.apply(). But Function.prototype.call() and Function.prototype.apply() are slower than the normal function invocation.</p> + + + + Major + + + + + + + false + false + no-useless-concat + Best Practices + + true + no-useless-concat + It's unnecessary to concatenate two strings together, such as: This code is likely the result of refactoring where a variable was removed from the concatenation (such as "a" + b + "b"). In such a case, the concatenation isn't important and the code can be rewritten as: + <p>It’s unnecessary to concatenate two strings together, such as: This code is likely the result of refactoring where a variable was removed from the concatenation (such as “a” + b + “b”). In such a case, the concatenation isn’t important and the code can be rewritten as:</p> + + + + Major + + + + + + + true + false + no-useless-escape + Best Practices + + true + no-useless-escape + Escaping non-special characters in strings, template literals, and regular expressions doesn’t have any effect, as demonstrated in the following example: + <p>Escaping non-special characters in strings, template literals, and regular expressions doesn’t have any effect, as demonstrated in the following example:</p> + + + + Major + + + + + + + false + false + no-useless-return + Best Practices + + true + no-useless-return + A return; statement with nothing after it is redundant, and has no effect on the runtime behavior of a function. This can be confusing, so it’s better to disallow these redundant statements. + <p>A return; statement with nothing after it is redundant, and has no effect on the runtime behavior of a function. This can be confusing, so it’s better to disallow these redundant statements.</p> + + + + Major + + + + + + + false + false + no-void + Best Practices + + true + no-void + The void operator takes an operand and returns undefined: void expression will evaluate expression and return undefined. It can be used to ignore any side effects expression may produce: The common case of using void operator is to get a "pure" undefined value as prior to ES5 the undefined variable was mutable: Another common case is to minify code as void 0 is shorter than undefined: When used with IIFE (immediately-invoked function expression) void can be used to force the function keyword to be treated as an expression instead of a declaration: Some code styles prohibit void operator marking it as non-obvious and hard to read. + <p>The void operator takes an operand and returns undefined: void expression will evaluate expression and return undefined. It can be used to ignore any side effects expression may produce: The common case of using void operator is to get a “pure” undefined value as prior to ES5 the undefined variable was mutable: Another common case is to minify code as void 0 is shorter than undefined: When used with IIFE (immediately-invoked function expression) void can be used to force the function keyword to be treated as an expression instead of a declaration: Some code styles prohibit void operator marking it as non-obvious and hard to read.</p> + + + + Major + + + + + + + false + false + no-warning-comments + Best Practices + + true + no-warning-comments + Often code is marked during development process for later work on it or with additional thoughts. Examples are typically // TODO: do something or // FIXME: this is not a good idea. These comments are a warning signal, that there is something not production ready in your code. Most likely you want to fix it or remove the comments before you roll out your code with a good feeling. + <p>Often code is marked during development process for later work on it or with additional thoughts. Examples are typically // TODO: do something or // FIXME: this is not a good idea. These comments are a warning signal, that there is something not production ready in your code. Most likely you want to fix it or remove the comments before you roll out your code with a good feeling.</p> + + + + Major + + { + "terms": [ "todo", "fixme", "xxx" ], + "location": "start" + } + + + + + + + + false + false + no-with + Best Practices + + true + no-with + The with statement is potentially problematic because it adds members of an object to the current scope, making it impossible to tell what a variable inside the block actually refers to. Additionally, the with statement cannot be used in strict mode. + <p>The with statement is potentially problematic because it adds members of an object to the current scope, making it impossible to tell what a variable inside the block actually refers to. Additionally, the with statement cannot be used in strict mode.</p> + + + + Major + + + + + + + false + false + prefer-promise-reject-errors + Best Practices + + true + prefer-promise-reject-errors + It is considered good practice to only pass instances of the built-in Error object to the reject() function for user-defined errors in Promises. Error objects automatically store a stack trace, which can be used to debug an error by determining where it came from. If a Promise is rejected with a non-Error value, it can be difficult to determine where the rejection occurred. + <p>It is considered good practice to only pass instances of the built-in Error object to the reject() function for user-defined errors in Promises. Error objects automatically store a stack trace, which can be used to debug an error by determining where it came from. If a Promise is rejected with a non-Error value, it can be difficult to determine where the rejection occurred.</p> + + + + Major + + + + + + + false + false + radix + Best Practices + + true + radix + When using the parseInt() function it is common to omit the second argument, the radix, and let the function try to determine from the first argument what type of number it is. By default, parseInt() will autodetect decimal and hexadecimal (via 0x prefix). Prior to ECMAScript 5, parseInt() also autodetected octal literals, which caused problems because many developers assumed a leading 0 would be ignored. This confusion led to the suggestion that you always use the radix parameter to parseInt() to eliminate unintended consequences. So instead of doing this: Do this: ECMAScript 5 changed the behavior of parseInt() so that it no longer autodetects octal literals and instead treats them as decimal literals. However, the differences between hexadecimal and decimal interpretation of the first parameter causes many developers to continue using the radix parameter to ensure the string is interpreted in the intended way. On the other hand, if the code is targeting only ES5-compliant environments passing the radix 10 may be redundant. In such a case you might want to disallow using such a radix. + <p>When using the parseInt() function it is common to omit the second argument, the radix, and let the function try to determine from the first argument what type of number it is. By default, parseInt() will autodetect decimal and hexadecimal (via 0x prefix). Prior to ECMAScript 5, parseInt() also autodetected octal literals, which caused problems because many developers assumed a leading 0 would be ignored. This confusion led to the suggestion that you always use the radix parameter to parseInt() to eliminate unintended consequences. So instead of doing this: Do this: ECMAScript 5 changed the behavior of parseInt() so that it no longer autodetects octal literals and instead treats them as decimal literals. However, the differences between hexadecimal and decimal interpretation of the first parameter causes many developers to continue using the radix parameter to ensure the string is interpreted in the intended way. On the other hand, if the code is targeting only ES5-compliant environments passing the radix 10 may be redundant. In such a case you might want to disallow using such a radix.</p> + + + + Major + "always" + + + + + + + false + false + require-await + Best Practices + + true + require-await + Async functions which have no await expression may be the unintentional result of refactoring. + <p>Async functions which have no await expression may be the unintentional result of refactoring.</p> + + + + Major + + + + + + + false + false + vars-on-top + Best Practices + + true + vars-on-top + The vars-on-top rule generates warnings when variable declarations are not used serially at the top of a function scope or the top of a program. By default variable declarations are always moved (“hoisted”) invisibly to the top of their containing scope by the JavaScript interpreter. This rule forces the programmer to represent that behaviour by manually moving the variable declaration to the top of its containing scope. + <p>The vars-on-top rule generates warnings when variable declarations are not used serially at the top of a function scope or the top of a program. By default variable declarations are always moved (“hoisted”) invisibly to the top of their containing scope by the JavaScript interpreter. This rule forces the programmer to represent that behaviour by manually moving the variable declaration to the top of its containing scope.</p> + + + + Major + + + + + + + false + false + wrap-iife + Best Practices + + true + wrap-iife + Require immediate function invocation to be wrapped in parentheses. + <p>Require immediate function invocation to be wrapped in parentheses.</p> + + + + Major + "outside" + + + + + + + false + false + yoda + Best Practices + + true + yoda + Yoda conditions are so named because the literal value of the condition comes first while the variable comes second. For example, the following is a Yoda condition: This is called a Yoda condition because it reads as, "red is the color", similar to the way the Star Wars character Yoda speaks. Compare to the other way of arranging the operands: This typically reads, "color is red", which is arguably a more natural way to describe the comparison. Proponents of Yoda conditions highlight that it is impossible to mistakenly use = instead of == because you cannot assign to a literal value. Doing so will cause a syntax error and you will be informed of the mistake early on. This practice was therefore very common in early programming where tools were not yet available. Opponents of Yoda conditions point out that tooling has made us better programmers because tools will catch the mistaken use of = instead of == (ESLint will catch this for you). Therefore, they argue, the utility of the pattern doesn't outweigh the readability hit the code takes while using Yoda conditions. + <p>Yoda conditions are so named because the literal value of the condition comes first while the variable comes second. For example, the following is a Yoda condition: This is called a Yoda condition because it reads as, “red is the color”, similar to the way the Star Wars character Yoda speaks. Compare to the other way of arranging the operands: This typically reads, “color is red”, which is arguably a more natural way to describe the comparison. Proponents of Yoda conditions highlight that it is impossible to mistakenly use = instead of == because you cannot assign to a literal value. Doing so will cause a syntax error and you will be informed of the mistake early on. This practice was therefore very common in early programming where tools were not yet available. Opponents of Yoda conditions point out that tooling has made us better programmers because tools will catch the mistaken use of = instead of == (ESLint will catch this for you). Therefore, they argue, the utility of the pattern doesn’t outweigh the readability hit the code takes while using Yoda conditions.</p> + + + + Major + "never" + + + + + + + + + + + + + + + + + + false + false + strict + Strict Mode + + true + strict + A Use Strict Directive at the beginning of a script or function body enables strict mode semantics: When used globally, as in the preceding example, the entire script, including all contained functions, are strict mode code. It is also possible to specify function-level strict mode, such that strict mode applies only to the function in which the directive occurs: + <p>A Use Strict Directive at the beginning of a script or function body enables strict mode semantics: When used globally, as in the preceding example, the entire script, including all contained functions, are strict mode code. It is also possible to specify function-level strict mode, such that strict mode applies only to the function in which the directive occurs:</p> + + + + Major + "safe" + + + + + + + + + + + + + + + + + + false + false + init-declarations + Variables + + true + init-declarations + In JavaScript, variables can be assigned during declaration, or at any point afterwards using an assignment statement. For example, in the following code, foo is initialized during declaration, while bar is initialized later. + <p>In JavaScript, variables can be assigned during declaration, or at any point afterwards using an assignment statement. For example, in the following code, foo is initialized during declaration, while bar is initialized later.</p> + + + + Major + { "ignoreForLoopInit": true } + + + + + + + false + false + no-catch-shadow + Variables + + true + no-catch-shadow + In IE 8 and earlier, the catch clause parameter can overwrite the value of a variable in the outer scope, if that variable has the same name as the catch clause parameter. + <p>In IE 8 and earlier, the catch clause parameter can overwrite the value of a variable in the outer scope, if that variable has the same name as the catch clause parameter.</p> + + + + Major + + + + + + + true + false + no-delete-var + Variables + + true + no-delete-var + The purpose of the delete operator is to remove a property from an object. Using the delete operator on a variable might lead to unexpected behavior. + <p>The purpose of the delete operator is to remove a property from an object. Using the delete operator on a variable might lead to unexpected behavior.</p> + + + + Major + + + + + + + false + false + no-label-var + Variables + + true + no-label-var + This rule aims to create clearer code by disallowing the bad practice of creating a label that shares a name with a variable that is in scope. + <p>This rule aims to create clearer code by disallowing the bad practice of creating a label that shares a name with a variable that is in scope.</p> + + + + Major + + + + + + + false + false + no-restricted-globals + Variables + + true + no-restricted-globals + Disallowing usage of specific global variables can be useful if you want to allow a set of global variables by enabling an environment, but still want to disallow some of those. + <p>Disallowing usage of specific global variables can be useful if you want to allow a set of global variables by enabling an environment, but still want to disallow some of those.</p> + + + + Major + "event" + + + + + + + false + false + no-shadow + Variables + + true + no-shadow + Shadowing is the process by which a local variable shares the same name as a variable in its containing scope. For example: In this case, the variable a inside of b() is shadowing the variable a in the global scope. This can cause confusion while reading the code and it's impossible to access the global variable. + <p>Shadowing is the process by which a local variable shares the same name as a variable in its containing scope. For example: In this case, the variable a inside of b() is shadowing the variable a in the global scope. This can cause confusion while reading the code and it’s impossible to access the global variable.</p> + + + + Major + + { + "builtinGlobals": false, + "hoist": "functions", + "allow": [] + } + + + + + + + false + false + no-shadow-restricted-names + Variables + + true + no-shadow-restricted-names + ES5 §15.1.1 Value Properties of the Global Object (NaN, Infinity, undefined) as well as strict mode restricted identifiers eval and arguments are considered to be restricted names in JavaScript. Defining them to mean something else can have unintended consequences and confuse others reading the code. For example, there's nothing prevent you from writing: Then any code used within the same scope would not get the global undefined, but rather the local version with a very different meaning. + <p>ES5 §15.1.1 Value Properties of the Global Object (NaN, Infinity, undefined) as well as strict mode restricted identifiers eval and arguments are considered to be restricted names in JavaScript. Defining them to mean something else can have unintended consequences and confuse others reading the code. For example, there’s nothing prevent you from writing: Then any code used within the same scope would not get the global undefined, but rather the local version with a very different meaning.</p> + + + + Major + + + + + + + true + false + no-undef + Variables + + true + no-undef + This rule can help you locate potential ReferenceErrors resulting from misspellings of variable and parameter names, or accidental implicit globals (for example, from forgetting the var keyword in a for loop initializer). + <p>This rule can help you locate potential ReferenceErrors resulting from misspellings of variable and parameter names, or accidental implicit globals (for example, from forgetting the var keyword in a for loop initializer).</p> + + + + Major + { "typeof": false } + + + + + + + false + false + no-undef-init + Variables + + true + no-undef-init + In JavaScript, a variable that is declared and not initialized to any value automatically gets the value of undefined. For example: It's therefore unnecessary to initialize a variable to undefined, such as: It's considered a best practice to avoid initializing variables to undefined. + <p>In JavaScript, a variable that is declared and not initialized to any value automatically gets the value of undefined. For example: It’s therefore unnecessary to initialize a variable to undefined, such as: It’s considered a best practice to avoid initializing variables to undefined.</p> + + + + Major + + + + + + + false + false + no-undefined + Variables + + true + no-undefined + The undefined variable is unique in JavaScript because it is actually a property of the global object. As such, in ECMAScript 3 it was possible to overwrite the value of undefined. While ECMAScript 5 disallows overwriting undefined, it's still possible to shadow undefined, such as: This represents a problem for undefined that doesn't exist for null, which is a keyword and primitive value that can neither be overwritten nor shadowed. All uninitialized variables automatically get the value of undefined: For this reason, it's not necessary to explicitly initialize a variable to undefined. Taking all of this into account, some style guides forbid the use of undefined, recommending instead: + <p>The undefined variable is unique in JavaScript because it is actually a property of the global object. As such, in ECMAScript 3 it was possible to overwrite the value of undefined. While ECMAScript 5 disallows overwriting undefined, it’s still possible to shadow undefined, such as: This represents a problem for undefined that doesn’t exist for null, which is a keyword and primitive value that can neither be overwritten nor shadowed. All uninitialized variables automatically get the value of undefined: For this reason, it’s not necessary to explicitly initialize a variable to undefined. Taking all of this into account, some style guides forbid the use of undefined, recommending instead:</p> + + + + Major + + + + + + + false + false + no-unused-vars + Variables + + true + no-unused-vars + Variables that are declared and not used anywhere in the code are most likely an error due to incomplete refactoring. Such variables take up space in the code and can lead to confusion by readers. + <p>Variables that are declared and not used anywhere in the code are most likely an error due to incomplete refactoring. Such variables take up space in the code and can lead to confusion by readers.</p> + + + + Major + + { + "vars": "all", + "args": "after-used" + } + + + + + + + + false + false + no-use-before-define + Variables + + true + no-use-before-define + In JavaScript, prior to ES6, variable and function declarations are hoisted to the top of a scope, so it's possible to use identifiers before their formal declarations in code. This can be confusing and some believe it is best to always declare variables and functions before using them. In ES6, block-level bindings (let and const) introduce a "temporal dead zone" where a ReferenceError will be thrown with any attempt to access the variable before its declaration. + <p>In JavaScript, prior to ES6, variable and function declarations are hoisted to the top of a scope, so it’s possible to use identifiers before their formal declarations in code. This can be confusing and some believe it is best to always declare variables and functions before using them. In ES6, block-level bindings (let and const) introduce a “temporal dead zone” where a ReferenceError will be thrown with any attempt to access the variable before its declaration.</p> + + + + Major + + { + "functions": true, + "classes": true, + "variables": true + } + + + + + + + + + + + + + + + + + false + false + callback-return + Node.js and CommonJS + + true + callback-return + The callback pattern is at the heart of most I/O and event-driven programming in JavaScript. To prevent calling the callback multiple times it is important to return anytime the callback is triggered outside of the main function body. Neglecting this technique often leads to issues where you do something more than once. For example, in the case of an HTTP request, you may try to send HTTP headers more than once leading node.js to throw a Can't render headers after they are sent to the client. error. + <p>The callback pattern is at the heart of most I/O and event-driven programming in JavaScript. To prevent calling the callback multiple times it is important to return anytime the callback is triggered outside of the main function body. Neglecting this technique often leads to issues where you do something more than once. For example, in the case of an HTTP request, you may try to send HTTP headers more than once leading node.js to throw a Can’t render headers after they are sent to the client. error.</p> + + + + Major + + + + + + + false + false + global-require + Node.js and CommonJS + + true + global-require + In Node.js, module dependencies are included using the require() function, such as: While require() may be called anywhere in code, some style guide prescribe that it should be called only in the top-level scope of a module to make it easier to identify dependencies. For instance, it's arguably harder to identify dependencies when they are deeply nested inside of functions and other statements: Since require() does a synchronous load, it can cause performance problems when used in other locations. + <p>In Node.js, module dependencies are included using the require() function, such as: While require() may be called anywhere in code, some style guide prescribe that it should be called only in the top-level scope of a module to make it easier to identify dependencies. For instance, it’s arguably harder to identify dependencies when they are deeply nested inside of functions and other statements: Since require() does a synchronous load, it can cause performance problems when used in other locations.</p> + + + + Major + + + + + + + false + false + handle-callback-err + Node.js and CommonJS + + true + handle-callback-err + In node, a common pattern for dealing with asynchronous behavior is called the callback pattern. This pattern expects an Error object or null as the first argument of the callback. Forgetting to handle these errors can lead to some really strange behavior in your application. + <p>In node, a common pattern for dealing with asynchronous behavior is called the callback pattern. This pattern expects an Error object or null as the first argument of the callback. Forgetting to handle these errors can lead to some really strange behavior in your application.</p> + + + + Major + "err" + + + + + + + false + false + no-buffer-constructor + Node.js and CommonJS + + true + no-buffer-constructor + In Node.js, the behavior of the Buffer constructor is different depending on the type of its argument. Passing an argument from user input to Buffer() without validating its type can lead to security vulnerabilities such as remote memory disclosure and denial of service. As a result, the Buffer constructor has been deprecated and should not be used. Use the producer methods Buffer.from, Buffer.alloc, and Buffer.allocUnsafe instead. + <p>In Node.js, the behavior of the Buffer constructor is different depending on the type of its argument. Passing an argument from user input to Buffer() without validating its type can lead to security vulnerabilities such as remote memory disclosure and denial of service. As a result, the Buffer constructor has been deprecated and should not be used. Use the producer methods Buffer.from, Buffer.alloc, and Buffer.allocUnsafe instead.</p> + + + + Major + "err" + + + + + + + false + false + no-mixed-requires + Node.js and CommonJS + + true + no-mixed-requires + In the Node.JS community it is often customary to separate the required modules from other variable declarations, sometimes also grouping them by their type. This rule helps you enforce this convention. + <p>In the Node.JS community it is often customary to separate the required modules from other variable declarations, sometimes also grouping them by their type. This rule helps you enforce this convention.</p> + + + + Major + { "grouping": false, "allowCall": false } + + + + + + + false + false + no-new-require + Node.js and CommonJS + + true + no-new-require + The require function is used to include modules that exist in separate files, such as: Some modules return a constructor which can potentially lead to code such as: Unfortunately, this introduces a high potential for confusion since the code author likely meant to write: For this reason, it is usually best to disallow this particular expression. + <p>The require function is used to include modules that exist in separate files, such as: Some modules return a constructor which can potentially lead to code such as: Unfortunately, this introduces a high potential for confusion since the code author likely meant to write: For this reason, it is usually best to disallow this particular expression.</p> + + + + Major + + + + + + + false + false + no-path-concat + Node.js and CommonJS + + true + no-path-concat + In Node.js, the __dirname and __filename global variables contain the directory path and the file path of the currently executing script file, respectively. Sometimes, developers try to use these variables to create paths to other files, such as: However, there are a few problems with this. First, you can't be sure what type of system the script is running on. Node.js can be run on any computer, including Windows, which uses a different path separator. It's very easy, therefore, to create an invalid path using string concatenation and assuming Unix-style separators. There's also the possibility of having double separators, or otherwise ending up with an invalid path. In order to avoid any confusion as to how to create the correct path, Node.js provides the path module. This module uses system-specific information to always return the correct value. So you can rewrite the previous example as: This example doesn't need to include separators as path.join() will do it in the most appropriate manner. Alternately, you can use path.resolve() to retrieve the fully-qualified path: Both path.join() and path.resolve() are suitable replacements for string concatenation wherever file or directory paths are being created. + <p>In Node.js, the __dirname and __filename global variables contain the directory path and the file path of the currently executing script file, respectively. Sometimes, developers try to use these variables to create paths to other files, such as: However, there are a few problems with this. First, you can’t be sure what type of system the script is running on. Node.js can be run on any computer, including Windows, which uses a different path separator. It’s very easy, therefore, to create an invalid path using string concatenation and assuming Unix-style separators. There’s also the possibility of having double separators, or otherwise ending up with an invalid path. In order to avoid any confusion as to how to create the correct path, Node.js provides the path module. This module uses system-specific information to always return the correct value. So you can rewrite the previous example as: This example doesn’t need to include separators as path.join() will do it in the most appropriate manner. Alternately, you can use path.resolve() to retrieve the fully-qualified path: Both path.join() and path.resolve() are suitable replacements for string concatenation wherever file or directory paths are being created.</p> + + + + Major + + + + + + + false + false + no-process-env + Best Practices + + true + no-process-env + The process.env object in Node.js is used to store deployment/configuration parameters. Littering it through out a project could lead to maintenance issues as it's another kind of global dependency. As such, it could lead to merge conflicts in a multi-user setup and deployment issues in a multi-server setup. Instead, one of the best practices is to define all those parameters in a single configuration/settings file which could be accessed throughout the project. + <p>The process.env object in Node.js is used to store deployment/configuration parameters. Littering it through out a project could lead to maintenance issues as it’s another kind of global dependency. As such, it could lead to merge conflicts in a multi-user setup and deployment issues in a multi-server setup. Instead, one of the best practices is to define all those parameters in a single configuration/settings file which could be accessed throughout the project.</p> + + + + Major + + + + + + + false + false + no-process-exit + Node.js and CommonJS + + true + no-process-exit + The process.exit() method in Node.js is used to immediately stop the Node.js process and exit. This is a dangerous operation because it can occur in any method at any point in time, potentially stopping a Node.js application completely when an error occurs. For example: This code could appear in any module and will stop the entire application when somethingBadHappened is truthy. This doesn't give the application any chance to respond to the error. It's usually better to throw an error and allow the application to handle it appropriately: By throwing an error in this way, other parts of the application have an opportunity to handle the error rather than stopping the application altogether. If the error bubbles all the way up to the process without being handled, then the process will exit and a non-zero exit code will returned, so the end result is the same. + <p>The process.exit() method in Node.js is used to immediately stop the Node.js process and exit. This is a dangerous operation because it can occur in any method at any point in time, potentially stopping a Node.js application completely when an error occurs. For example: This code could appear in any module and will stop the entire application when somethingBadHappened is truthy. This doesn’t give the application any chance to respond to the error. It’s usually better to throw an error and allow the application to handle it appropriately: By throwing an error in this way, other parts of the application have an opportunity to handle the error rather than stopping the application altogether. If the error bubbles all the way up to the process without being handled, then the process will exit and a non-zero exit code will returned, so the end result is the same.</p> + + + + Major + + + + + + + false + false + no-restricted-modules + Node.js and CommonJS + + true + no-restricted-modules + Disallowing usage of specific node modules can be useful if you want to control the available methods, a developer can use, to implement a feature. This way you can block usage of the fs module if you want disallow file system access. Blocking the os module can be useful if you don't want to allow any operating system specific code. + <p>Disallowing usage of specific node modules can be useful if you want to control the available methods, a developer can use, to implement a feature. This way you can block usage of the fs module if you want disallow file system access. Blocking the os module can be useful if you don’t want to allow any operating system specific code.</p> + + + + Major + { "paths": [] } + + + + + + + false + false + no-sync + Node.js and CommonJS + + true + no-sync + In Node.js, most I/O is done through asynchronous methods. However, there are often synchronous versions of the asynchronous methods. For example, fs.exists() and fs.existsSync(). In some contexts, using synchronous operations is okay (if, as with ESLint, you are writing a command line utility). However, in other contexts the use of synchronous operations is considered a bad practice that should be avoided. For example, if you are running a high-travel web server on Node.js, you should consider carefully if you want to allow any synchronous operations that could lock up the server. + <p>In Node.js, most I/O is done through asynchronous methods. However, there are often synchronous versions of the asynchronous methods. For example, fs.exists() and fs.existsSync(). In some contexts, using synchronous operations is okay (if, as with ESLint, you are writing a command line utility). However, in other contexts the use of synchronous operations is considered a bad practice that should be avoided. For example, if you are running a high-travel web server on Node.js, you should consider carefully if you want to allow any synchronous operations that could lock up the server.</p> + + + + Major + { "allowAtRootLevel": false } + + + + + + + + + + + + + + + + false + false + array-bracket-newline + Stylistic Issues + + true + array-bracket-newline + A number of style guides require or disallow line breaks inside of array brackets. + <p>A number of style guides require or disallow line breaks inside of array brackets.</p> + + + + Major + + { "multiline": true, "minItems": 2 } + + + + + + + + false + false + array-bracket-spacing + Stylistic Issues + + true + array-bracket-spacing + A number of style guides require or disallow spaces between array brackets and other tokens. This rule applies to both array literals and destructuring assignments (ECMAScript 6). + <p>A number of style guides require or disallow spaces between array brackets and other tokens. This rule applies to both array literals and destructuring assignments (ECMAScript 6).</p> + + + + Major + + "always" + + + + + + + + false + false + array-element-newline + Stylistic Issues + + true + array-element-newline + A number of style guides require or disallow line breaks between array elements. + <p>A number of style guides require or disallow line breaks between array elements.</p> + + + + Major + + "always" + + + + + + + + false + false + block-spacing + Stylistic Issues + + true + block-spacing + This rule is for spacing style within single line blocks. Fixable: This rule is automatically fixable using the --fix flag on the command line. + <p>This rule is for spacing style within single line blocks. Fixable: This rule is automatically fixable using the –fix flag on the command line.</p> + + + + Major + "always" + + + + + + + false + false + brace-style + Stylistic Issues + + true + brace-style + Brace style is closely related to indent style in programming and describes the placement of curly braces relative to their control statement and body. There are probably a dozen, if not more, brace styles in the world. The one true brace style is one of the most common brace styles in JavaScript, in which the opening curly brace of a block is placed on the same line as its corresponding statement or declaration. For example: One common variant of one true brace style is called Stroustrup, in which the else statements in an if-else construct, as well as catch and finally, must be on its own line after the preceding closing brace, as in this example: Another style is called Allman, in which all the braces are expected to be on their own lines without any extra indentation: While no style is considered better than the other, most developers agree that having a consistent style throughout a project is important for its long-term maintainability. + <p>Brace style is closely related to indent style in programming and describes the placement of curly braces relative to their control statement and body. There are probably a dozen, if not more, brace styles in the world. The one true brace style is one of the most common brace styles in JavaScript, in which the opening curly brace of a block is placed on the same line as its corresponding statement or declaration. For example: One common variant of one true brace style is called Stroustrup, in which the else statements in an if-else construct, as well as catch and finally, must be on its own line after the preceding closing brace, as in this example: Another style is called Allman, in which all the braces are expected to be on their own lines without any extra indentation: While no style is considered better than the other, most developers agree that having a consistent style throughout a project is important for its long-term maintainability.</p> + + + + Major + "1tbs" + + + + + + + false + false + camelcase + Stylistic Issues + + true + camelcase + When it comes to naming variables, styleguides generally fall into one of two camps: camelcase (variableName) and underscores (variable_name). This rule focuses on using the camelcase approach. If your styleguide calls for camelcasing your variable names, then this rule is for you! + <p>When it comes to naming variables, styleguides generally fall into one of two camps: camelcase (variableName) and underscores (variable_name). This rule focuses on using the camelcase approach. If your styleguide calls for camelcasing your variable names, then this rule is for you!</p> + + + + Major + { "properties": "always" } + + + + + + + false + false + capitalized-comments + Stylistic Issues + + true + capitalized-comments + Comments are useful for leaving information for future developers. In order for that information to be useful and not distracting, it is sometimes desirable for comments to follow a particular style. One element of comment formatting styles is whether the first word of a comment should be capitalized or lowercase. In general, no comment style is any more or less valid than any others, but many developers would agree that a consistent style can improve a project’s maintainability. + <p>Comments are useful for leaving information for future developers. In order for that information to be useful and not distracting, it is sometimes desirable for comments to follow a particular style. One element of comment formatting styles is whether the first word of a comment should be capitalized or lowercase. In general, no comment style is any more or less valid than any others, but many developers would agree that a consistent style can improve a project’s maintainability.</p> + + + + Major + "always" + + + + + + + + false + false + comma-dangle + Possible Errors + + true + comma-dangle + Trailing commas in object literals are valid according to the ECMAScript 5 (and ECMAScript 3!) spec. However, IE8 (when not in IE8 document mode) and below will throw an error when it encounters trailing commas in JavaScript. On the other hand, trailing commas simplify adding and removing items to objects and arrays, since only the lines you are modifying must be touched. + <p>Trailing commas in object literals are valid according to the ECMAScript 5 (and ECMAScript 3!) spec. However, IE8 (when not in IE8 document mode) and below will throw an error when it encounters trailing commas in JavaScript. On the other hand, trailing commas simplify adding and removing items to objects and arrays, since only the lines you are modifying must be touched.</p> + + + + Major + + { + "arrays": "never", + "objects": "never", + "imports": "never", + "exports": "never", + "functions": "ignore" + } + + + + + + + + false + false + comma-spacing + Stylistic Issues + + true + comma-spacing + Spacing around commas improve readability of a list of items. Although most of the style guidelines for languages prescribe adding a space after a comma and not before it, it is subjective to the preferences of a project. + <p>Spacing around commas improve readability of a list of items. Although most of the style guidelines for languages prescribe adding a space after a comma and not before it, it is subjective to the preferences of a project.</p> + + + + Major + + { + "before": false, + "after": true + } + + + + + + + false + false + comma-style + Stylistic Issues + + true + comma-style + Comma Style rule enforces comma styles for a list of things separated by commas. There are two comma styles primarily in JavaScript. The standard one in which commas are placed at the end of the line. And Comma-First, in which, commas are placed at the start of the next line after the list item. One of the justifications for using Comma-First is that it helps tracking missing and trailing commas. In case linting is turned off, missing commas in variable declarations lead to leakage of global variables and trailing commas lead to errors in older versions of IE. + <p>Comma Style rule enforces comma styles for a list of things separated by commas. There are two comma styles primarily in JavaScript. The standard one in which commas are placed at the end of the line. And Comma-First, in which, commas are placed at the start of the next line after the list item. One of the justifications for using Comma-First is that it helps tracking missing and trailing commas. In case linting is turned off, missing commas in variable declarations lead to leakage of global variables and trailing commas lead to errors in older versions of IE.</p> + + + + Major + "last" + + + + + + + false + false + computed-property-spacing + Stylistic Issues + + true + computed-property-spacing + While formatting preferences are very personal, a number of style guides require or disallow spaces between computed properties in the following situations: Fixable: This rule is automatically fixable using the --fix flag on the command line. + <p>While formatting preferences are very personal, a number of style guides require or disallow spaces between computed properties in the following situations: Fixable: This rule is automatically fixable using the –fix flag on the command line.</p> + + + + Major + "always" + + + + + + + false + false + consistent-this + Stylistic Issues + + true + consistent-this + It is often necessary to capture the current execution context in order to make it available subsequently. A prominent example of this are jQuery callbacks: There are many commonly used aliases for this such as self, that or me. It is desirable to ensure that whichever alias the team agrees upon is used consistently throughout the application. + <p>It is often necessary to capture the current execution context in order to make it available subsequently. A prominent example of this are jQuery callbacks: There are many commonly used aliases for this such as self, that or me. It is desirable to ensure that whichever alias the team agrees upon is used consistently throughout the application.</p> + + + + Major + "that" + + + + + + + false + false + eol-last + Stylistic Issues + + true + eol-last + Trailing newlines in non-empty files are a common UNIX idiom. Benefits of trailing newlines include the ability to concatenate or append to files as well as output files to the terminal without interfering with shell prompts. + <p>Trailing newlines in non-empty files are a common UNIX idiom. Benefits of trailing newlines include the ability to concatenate or append to files as well as output files to the terminal without interfering with shell prompts.</p> + + + + Major + "always" + + + + + + + false + false + func-call-spacing + Stylistic Issues + + true + func-call-spacing + When calling a function, developers may insert optional whitespace between the function’s name and the parentheses that invoke it. + <p>When calling a function, developers may insert optional whitespace between the function’s name and the parentheses that invoke it.</p> + + + + Major + "never" + + + + + + + false + false + func-name-matching + Stylistic Issues + + true + func-name-matching + This rule requires function names to match the name of the variable or property to which they are assigned. The rule will ignore property assignments where the property name is a literal that is not a valid identifier in the ECMAScript version specified in your configuration (default ES5). + <p>This rule requires function names to match the name of the variable or property to which they are assigned. The rule will ignore property assignments where the property name is a literal that is not a valid identifier in the ECMAScript version specified in your configuration (default ES5).</p> + + + + Major + "always" + + + + + + + false + false + func-names + Stylistic Issues + + true + func-names + A pattern that's becoming more common is to give function expressions names to aid in debugging, such as: Adding the second bar in the above example is optional. If you leave off the function name then when the function throws an exception you are likely to get something similar to anonymous function in the stack trace. If you provide the optional name for a function expression then you will get the name of the function expression in the stack trace. + <p>A pattern that’s becoming more common is to give function expressions names to aid in debugging, such as: Adding the second bar in the above example is optional. If you leave off the function name then when the function throws an exception you are likely to get something similar to anonymous function in the stack trace. If you provide the optional name for a function expression then you will get the name of the function expression in the stack trace.</p> + + + + Major + "always" + + + + + + + false + false + func-style + Stylistic Issues + + true + func-style + There are two ways of defining functions in JavaScript: function declarations and function expressions. Declarations have the function keyword first, followed by a name, followed by its arguments and the function body, such as: Equivalent function expressions begin with the var keyword, followed by a name, and then the function itself, such as: The primary difference between function declarations and function expressions is that declarations are hoisted to the top of the scope in which they are defined, which allows you to write code that uses the function before the declaration. For example: Although this code might seem like an error, it actually works fine because JavaScript engines hoist the function declarations to the top of the scope. That means this code is treated as if the declaration came before the invocation. For function expressions, you must define the function before it is used, otherwise it causes an error. Example: In this case, doSomething() is undefined at the time of invocation and so causes a runtime error. Due to these different behaviors, it is common to have guidelines as to which style of function should be used. There is really no correct or incorrect choice here, it is just a preference. + <p>There are two ways of defining functions in JavaScript: function declarations and function expressions. Declarations have the function keyword first, followed by a name, followed by its arguments and the function body, such as: Equivalent function expressions begin with the var keyword, followed by a name, and then the function itself, such as: The primary difference between function declarations and function expressions is that declarations are hoisted to the top of the scope in which they are defined, which allows you to write code that uses the function before the declaration. For example: Although this code might seem like an error, it actually works fine because JavaScript engines hoist the function declarations to the top of the scope. That means this code is treated as if the declaration came before the invocation. For function expressions, you must define the function before it is used, otherwise it causes an error. Example: In this case, doSomething() is undefined at the time of invocation and so causes a runtime error. Due to these different behaviors, it is common to have guidelines as to which style of function should be used. There is really no correct or incorrect choice here, it is just a preference.</p> + + + + Major + "expression" + + + + + + + false + false + function-paren-newline + Stylistic Issues + + true + function-paren-newline + Many style guides require or disallow newlines inside of function parentheses. + <p>Many style guides require or disallow newlines inside of function parentheses.</p> + + + + Major + "multiline" + + + + + + + false + false + id-blacklist + Stylistic Issues + + true + id-blacklist + Bad names can lead to hard-to-decipher code. Generic names, such as data, don’t infer much about the code and the values it receives. This rule allows you to configure a blacklist of bad identifier names, that you don’t want to see in your code. + <p>Bad names can lead to hard-to-decipher code. Generic names, such as data, don’t infer much about the code and the values it receives. This rule allows you to configure a blacklist of bad identifier names, that you don’t want to see in your code.</p> + + + + Major + "data" + + + + + + + false + false + id-length + Stylistic Issues + + true + id-length + Very short identifier names like e, x, _t or very long ones like hashGeneratorResultOutputContainerObject usually make the code harder to read and potentially less maintainable. To prevent this, one may enforce a minimum and/or maximum identifier length. (usually min 2-chars) + <p>Very short identifier names like e, x, _t or very long ones like hashGeneratorResultOutputContainerObject usually make the code harder to read and potentially less maintainable. To prevent this, one may enforce a minimum and/or maximum identifier length. (usually min 2-chars)</p> + + + + Major + + { + "min": 2, + "properties": "always" + } + + + + + + + + false + false + id-match + Stylistic Issues + + true + id-match + Naming things consistently in a project is an often underestimated aspect of code creation. When done right, it can save your team hours of unnecessary head scratching and misdirections. This rule allows you to precisely define and enforce the variables and function names on your team should use. No more limiting yourself to camelCase, snake_case, PascalCase or oHungarianNotation. Id-match has all your needs covered! + <p>Naming things consistently in a project is an often underestimated aspect of code creation. When done right, it can save your team hours of unnecessary head scratching and misdirections. This rule allows you to precisely define and enforce the variables and function names on your team should use. No more limiting yourself to camelCase, snake_case, PascalCase or oHungarianNotation. Id-match has all your needs covered!</p> + + + + Major + "^[a-z]+([A-Z][a-z]+)*$" + + + + + + + false + false + implicit-arrow-linebreak + Stylistic Issues + + true + implicit-arrow-linebreak + An arrow function body can contain an implicit return as an expression instead of a block body. It can be useful to enforce a consistent location for the implicitly returned expression. + <p>An arrow function body can contain an implicit return as an expression instead of a block body. It can be useful to enforce a consistent location for the implicitly returned expression.</p> + + + + Major + "beside" + + + + + + + false + false + indent + Stylistic Issues + + true + indent + There are several common guidelines which require specific indentation of nested blocks and statements. + <p>There are several common guidelines which require specific indentation of nested blocks and statements.</p> + + + + Major + 2 + + + + + + + false + false + jsx-quotes + Stylistic Issues + + true + jsx-quotes + JSX attribute values can contain string literals, which are delimited with single or double quotes. Unlike string literals in JavaScript, string literals within JSX attributes can’t contain escaped quotes. If you want to have e.g. a double quote within a JSX attribute value, you have to use single quotes as string delimiter. + <p>JSX attribute values can contain string literals, which are delimited with single or double quotes. Unlike string literals in JavaScript, string literals within JSX attributes can’t contain escaped quotes. If you want to have e.g. a double quote within a JSX attribute value, you have to use single quotes as string delimiter.</p> + + + + Major + "prefer-double" + + + + + + + false + false + key-spacing + Stylistic Issues + + true + key-spacing + This rule enforces spacing around the colon in object literal properties. It can verify each property individually, or it can ensure vertical alignment of groups of properties in an object literal. + <p>This rule enforces spacing around the colon in object literal properties. It can verify each property individually, or it can ensure vertical alignment of groups of properties in an object literal.</p> + + + + Major + + { + "beforeColon": false, + "afterColon": true, + "mode": "strict" + } + + + + + + + + false + false + keyword-spacing + Stylistic Issues + + true + keyword-spacing + Keywords are syntax elements of JavaScript, such as function and if. These identifiers have special meaning to the language and so often appear in a different color in code editors. As an important part of the language, style guides often refer to the spacing that should be used around keywords. For example, you might have a style guide that says keywords should be always surrounded by spaces. + <p>Keywords are syntax elements of JavaScript, such as function and if. These identifiers have special meaning to the language and so often appear in a different color in code editors. As an important part of the language, style guides often refer to the spacing that should be used around keywords. For example, you might have a style guide that says keywords should be always surrounded by spaces. </p> + + + + Major + + { + "before": true, + "after": true, + "overrides":{} + } + + + + + + + + false + false + line-comment-position + Stylistic Issues + + true + line-comment-position + Line comments can be positioned above or beside code. This rule helps teams maintain a consistent style. + <p>Line comments can be positioned above or beside code. This rule helps teams maintain a consistent style.</p> + + + + Major + + { "position": "above" } + + + + + + + + false + false + linebreak-style + Stylistic Issues + + true + linebreak-style + When developing with a lot of people all having different editors, VCS applications and operating systems it may occur that different line endings are written by either of the mentioned (might especially happen when using the windows and mac versions of SourceTree together). The linebreaks (new lines) used in windows operating system are usually carriage returns (CR) followed by a line feed (LF) making it a carriage return line feed (CRLF) whereas Linux and Unix use a simple line feed (LF). The corresponding control sequences are "\n" (for LF) and "\r\n" for (CRLF). Many versioning systems (like git and subversion) can automatically ensure the correct ending. However to cover all contingencies you can activate this rule. + <p>When developing with a lot of people all having different editors, VCS applications and operating systems it may occur that different line endings are written by either of the mentioned (might especially happen when using the windows and mac versions of SourceTree together). The linebreaks (new lines) used in windows operating system are usually carriage returns (CR) followed by a line feed (LF) making it a carriage return line feed (CRLF) whereas Linux and Unix use a simple line feed (LF). The corresponding control sequences are “” (for LF) and “” for (CRLF). Many versioning systems (like git and subversion) can automatically ensure the correct ending. However to cover all contingencies you can activate this rule.</p> + + + + Major + "unix" + + + + + + + false + false + lines-around-comment + Stylistic Issues + + true + lines-around-comment + Many style guides require empty lines before or after comments. The primary goal of these rules is to make the comments easier to read and improve readability of the code. + <p>Many style guides require empty lines before or after comments. The primary goal of these rules is to make the comments easier to read and improve readability of the code.</p> + + + + Major + + { + "beforeBlockComment": true + } + + + + + + + + false + false + lines-between-class-members + Stylistic Issues + + true + lines-between-class-members + This rule improves readability by enforcing lines between class members. It will not check empty lines before the first member and after the last member, since that is already taken care of by padded-blocks. + <p>This rule improves readability by enforcing lines between class members. It will not check empty lines before the first member and after the last member, since that is already taken care of by padded-blocks.</p> + + + + Major + "always" + + + + + + + false + false + max-depth + Stylistic Issues + + true + max-depth + Many developers consider code difficult to read if blocks are nested beyond a certain depth. + <p>Many developers consider code difficult to read if blocks are nested beyond a certain depth.</p> + + + + Major + { "max": 4 } + + + + + + + false + false + max-len + Stylistic Issues + + true + max-len + Very long lines of code in any language can be difficult to read. In order to aid in readability and maintainability many coders have developed a convention to limit lines of code to X number of characters (traditionally 80 characters). + <p>Very long lines of code in any language can be difficult to read. In order to aid in readability and maintainability many coders have developed a convention to limit lines of code to X number of characters (traditionally 80 characters).</p> + + + + Major + + { + "code": 80, + "tabWidth": 4, + "comments": 65, + "ignoreComments": true, + "ignoreTrailingComments": true, + "ignoreUrls": true, + "ignoreStrings": true, + "ignoreTemplateLiterals": true, + "ignoreRegExpLiterals": true + } + + + + + + + + false + false + max-lines + Stylistic Issues + + true + max-lines + Some people consider large files a code smell. Large files tend to do a lot of things and can make it hard following what’s going. While there is not an objective maximum number of lines considered acceptable in a file, most people would agree it should not be in the thousands. Recommendations usually range from 100 to 500 lines. + <p>Some people consider large files a code smell. Large files tend to do a lot of things and can make it hard following what’s going. While there is not an objective maximum number of lines considered acceptable in a file, most people would agree it should not be in the thousands. Recommendations usually range from 100 to 500 lines.</p> + + + + Major + + { + "max": 300, + "skipBlankLines": true, + "skipComments": true + } + + + + + + + + false + false + max-nested-callbacks + Stylistic Issues + + true + max-nested-callbacks + Many JavaScript libraries use the callback pattern to manage asynchronous operations. A program of any complexity will most likely need to manage several asynchronous operations at various levels of concurrency. A common pitfall that is easy to fall into is nesting callbacks, which makes code more difficult to read the deeper the callbacks are nested. + <p>Many JavaScript libraries use the callback pattern to manage asynchronous operations. A program of any complexity will most likely need to manage several asynchronous operations at various levels of concurrency. A common pitfall that is easy to fall into is nesting callbacks, which makes code more difficult to read the deeper the callbacks are nested.</p> + + + + Major + { "max": 10 } + + + + + + + false + false + max-params + Stylistic Issues + + true + max-params + Functions that take numerous parameters can be difficult to read and write because it requires the memorization of what each parameter is, its type, and the order they should appear in. As a result, many coders adhere to a convention that caps the number of parameters a function can take. + <p>Functions that take numerous parameters can be difficult to read and write because it requires the memorization of what each parameter is, its type, and the order they should appear in. As a result, many coders adhere to a convention that caps the number of parameters a function can take.</p> + + + + Major + { "max": 3 } + + + + + + + false + false + max-statements + Stylistic Issues + + true + max-statements + The max-statements rule allows you to specify the maximum number of statements allowed in a function. + <p>The max-statements rule allows you to specify the maximum number of statements allowed in a function.</p> + + + + Major + { "max": 10 } + + + + + + + false + false + max-statements-per-line + Stylistic Issues + + true + max-statements-per-line + A line of code containing too many statements can be difficult to read. Code is generally read from the top down, especially when scanning, so limiting the number of statements allowed on a single line can be very beneficial for readability and maintainability. + <p>A line of code containing too many statements can be difficult to read. Code is generally read from the top down, especially when scanning, so limiting the number of statements allowed on a single line can be very beneficial for readability and maintainability.</p> + + + + Major + { "max": 1 } + + + + + + + false + false + multiline-comment-style + Stylistic Issues + + true + multiline-comment-style + Many style guides require a particular style for comments that span multiple lines. For example, some style guides prefer the use of a single block comment for multiline comments, whereas other style guides prefer consecutive line comments. + <p>Many style guides require a particular style for comments that span multiple lines. For example, some style guides prefer the use of a single block comment for multiline comments, whereas other style guides prefer consecutive line comments.</p> + + + + Major + "starred-block" + + + + + + + false + false + multiline-ternary + Stylistic Issues + + true + multiline-ternary + JavaScript allows operands of ternary expressions to be separated by newlines, which can improve the readability of your program. + <p>JavaScript allows operands of ternary expressions to be separated by newlines, which can improve the readability of your program.</p> + + + + Major + "always" + + + + + + + false + false + new-cap + Stylistic Issues + + true + new-cap + The new operator in JavaScript creates a new instance of a particular type of object. That type of object is represented by a constructor function. Since constructor functions are just regular functions, the only defining characteristic is that new is being used as part of the call. Native JavaScript functions begin with an uppercase letter to distinguish those functions that are to be used as constructors from functions that are not. Many style guides recommend following this pattern to more easily determine which functions are to be used as constructors. + <p>The new operator in JavaScript creates a new instance of a particular type of object. That type of object is represented by a constructor function. Since constructor functions are just regular functions, the only defining characteristic is that new is being used as part of the call. Native JavaScript functions begin with an uppercase letter to distinguish those functions that are to be used as constructors from functions that are not. Many style guides recommend following this pattern to more easily determine which functions are to be used as constructors.</p> + + + + Major + + { + "newIsCap": true, + "capIsNew": true, + "properties": true + } + + + + + + + + false + false + new-parens + Stylistic Issues + + true + new-parens + JavaScript allows the omission of parentheses when invoking a function via the new keyword and the constructor has no arguments. However, some coders believe that omitting the parentheses is inconsistent with the rest of the language and thus makes code less clear. + <p>JavaScript allows the omission of parentheses when invoking a function via the new keyword and the constructor has no arguments. However, some coders believe that omitting the parentheses is inconsistent with the rest of the language and thus makes code less clear.</p> + + + + Major + + + + + + + false + false + newline-per-chained-call + Stylistic Issues + + true + newline-per-chained-call + Chained method calls on a single line without line breaks are harder to read, so some developers place a newline character after each method call in the chain to make it more readable and easy to maintain. + <p>Chained method calls on a single line without line breaks are harder to read, so some developers place a newline character after each method call in the chain to make it more readable and easy to maintain.</p> + + + + Major + { "ignoreChainWithDepth": 2 } + + + + + + + false + false + no-array-constructor + Stylistic Issues + + true + no-array-constructor + Use of the Array constructor to construct a new array is generally discouraged in favour of array literal notation because of the single-argument pitfall and because the Array global may be redefined. The exception is when the Array constructor is used to intentionally create sparse arrays of a specified size by giving the constructor a single numeric argument. + <p>Use of the Array constructor to construct a new array is generally discouraged in favour of array literal notation because of the single-argument pitfall and because the Array global may be redefined. The exception is when the Array constructor is used to intentionally create sparse arrays of a specified size by giving the constructor a single numeric argument.</p> + + + + Major + + + + + + + false + false + no-bitwise + Stylistic Issues + + true + no-bitwise + The use of bitwise operators in JavaScript is very rare and often & or | is simply a mistyped && or ||, which will lead to unexpected behavior. + <p>The use of bitwise operators in JavaScript is very rare and often &amp; or | is simply a mistyped &amp;&amp; or ||, which will lead to unexpected behavior.</p> + + + + Major + + { + "allow": ["~"], + "int32Hint": true + } + + + + + + + + false + false + no-continue + Stylistic Issues + + true + no-continue + The continue statement terminates execution of the statements in the current iteration of the current or labeled loop, and continues execution of the loop with the next iteration. When used incorrectly it makes code less testable, less readable and less maintainable. Structured control flow statements such as if should be used instead. + <p>The continue statement terminates execution of the statements in the current iteration of the current or labeled loop, and continues execution of the loop with the next iteration. When used incorrectly it makes code less testable, less readable and less maintainable. Structured control flow statements such as if should be used instead.</p> + + + + Major + + + + + + + false + false + no-inline-comments + Stylistic Issues + + true + no-inline-comments + Some style guides disallow a comments on the same line as code. If there are comments immediately following code, it can make it harder to read the code. On the other hand, it is sometimes faster and more obvious to put comments immediately following code. + <p>Some style guides disallow a comments on the same line as code. If there are comments immediately following code, it can make it harder to read the code. On the other hand, it is sometimes faster and more obvious to put comments immediately following code.</p> + + + + Major + + + + + + + false + false + no-lonely-if + Stylistic Issues + + true + no-lonely-if + If an if statement is the only statement in the else block of a parent if statement, it is often clearer to combine the two to using else if form. should be rewritten as + <p>If an if statement is the only statement in the else block of a parent if statement, it is often clearer to combine the two to using else if form. should be rewritten as</p> + + + + Major + + + + + + + false + false + no-mixed-operators + Stylistic Issues + + true + no-mixed-operators + Enclosing complex expressions by parentheses clarifies the developer’s intention, which makes the code more readable. This rule warns when different operators are used consecutively without parentheses in an expression. + <p>Enclosing complex expressions by parentheses clarifies the developer’s intention, which makes the code more readable. This rule warns when different operators are used consecutively without parentheses in an expression.</p> + + + + Major + + { + "groups": [ + ["+", "-", "*", "/", "%", "**"], + ["&", "|", "^", "~", "<<", ">>", ">>>"], + ["==", "!=", "===", "!==", ">", ">=", "<", "<="], + ["&&", "||"], + ["in", "instanceof"] + ], + "allowSamePrecedence": true + } + + + + + + + + true + false + no-mixed-spaces-and-tabs + Stylistic Issues + + true + no-mixed-spaces-and-tabs + Most code conventions require either tabs or spaces be used for indentation. As such, it's usually an error if a single line of code is indented with both tabs and spaces. + <p>Most code conventions require either tabs or spaces be used for indentation. As such, it’s usually an error if a single line of code is indented with both tabs and spaces.</p> + + + + Major + + + + + + + + false + false + no-multi-assign + Stylistic Issues + + true + no-multi-assign + Chaining the assignment of variables can lead to unexpected results and be difficult to read. + <p>Chaining the assignment of variables can lead to unexpected results and be difficult to read.</p> + + + + Major + + + + + + + false + false + no-multiple-empty-lines + Stylistic Issues + + true + no-multiple-empty-lines + Some developers prefer to have multiple blank lines removed, while others feel that it helps improve readability. Whitespace is useful for separating logical sections of code, but excess whitespace takes up more of the screen. + <p>Some developers prefer to have multiple blank lines removed, while others feel that it helps improve readability. Whitespace is useful for separating logical sections of code, but excess whitespace takes up more of the screen.</p> + + + + Major + { "max": 1 } + + + + + + + false + false + no-negated-condition + Stylistic Issues + + true + no-negated-condition + Negated conditions are more difficult to understand. Code can be made more readable by inverting the condition instead. + <p>Negated conditions are more difficult to understand. Code can be made more readable by inverting the condition instead.</p> + + + + Major + + + + + + + false + false + no-nested-ternary + Stylistic Issues + + true + no-nested-ternary + Nesting ternary expressions makes code unclear. The no-nested-ternary rule disallows the use of nested ternary expressions. + <p>Nesting ternary expressions makes code unclear. The no-nested-ternary rule disallows the use of nested ternary expressions.</p> + + + + Major + + + + + + + false + false + no-new-object + Stylistic Issues + + true + no-new-object + The Object constructor is used to create new generic objects in JavaScript, such as: However, this is no different from using the more concise object literal syntax: For this reason, many prefer to always use the object literal syntax and never use the Object constructor. While there are no performance differences between the two approaches, the byte savings and conciseness of the object literal form is what has made it the de facto way of creating new objects. + <p>The Object constructor is used to create new generic objects in JavaScript, such as: However, this is no different from using the more concise object literal syntax: For this reason, many prefer to always use the object literal syntax and never use the Object constructor. While there are no performance differences between the two approaches, the byte savings and conciseness of the object literal form is what has made it the de facto way of creating new objects.</p> + + + + Major + + + + + + + false + false + no-plusplus + Stylistic Issues + + true + no-plusplus + Because the unary ++ and -- operators are subject to automatic semicolon insertion, differences in whitespace can change semantics of source code. + <p>Because the unary ++ and -- operators are subject to automatic semicolon insertion, differences in whitespace can change semantics of source code.</p> + + + + Major + { "allowForLoopAfterthoughts": true } + + + + + + + false + false + no-restricted-syntax + Stylistic Issues + + true + no-restricted-syntax + JavaScript has a lot of language features, and not everyone likes every features. As a result, some projects choose to disallow the use of certain language features altogether. For instance, you might decide to disallow the use of try-catch or class. Rather than creating separate rules for every language feature you want to turn off, this rule allows you to configure the syntax elements you want to restrict use of. These elements are represented by their ESTree node types. For example, a function declaration is represented by FunctionDeclaration and the with statement is represented by WithStatement. You may find the full list of AST node names you can use on GitHub and use the online parser to see what type of nodes your code consists of. + <p>JavaScript has a lot of language features, and not everyone likes every features. As a result, some projects choose to disallow the use of certain language features altogether. For instance, you might decide to disallow the use of try-catch or class. Rather than creating separate rules for every language feature you want to turn off, this rule allows you to configure the syntax elements you want to restrict use of. These elements are represented by their ESTree node types. For example, a function declaration is represented by FunctionDeclaration and the with statement is represented by WithStatement. You may find the full list of AST node names you can use on GitHub and use the online parser to see what type of nodes your code consists of.</p> + + + + Major + + + + + + + + false + false + no-tabs + Stylistic Issues + + true + no-tabs + Some style guides don’t allow the use of tab characters at all, including within comments. + <p>Some style guides don’t allow the use of tab characters at all, including within comments.</p> + + + + Major + + + + + + + + false + false + no-ternary + Stylistic Issues + + true + no-ternary + The ternary operator is used to conditionally assign a value to a variable. Some believe that the use of ternary operators leads to unclear code. + <p>The ternary operator is used to conditionally assign a value to a variable. Some believe that the use of ternary operators leads to unclear code.</p> + + + + Major + + + + + + + false + false + no-trailing-spaces + Stylistic Issues + + true + no-trailing-spaces + Sometimes in the course of editing files, you can end up with extra whitespace at the end of lines. These whitespace differences can be picked up by source control systems and flagged as diffs, causing frustration for developers. While this extra whitespace causes no functional issues, many code conventions require that trailing spaces be removed before checkin. Fixable: This rule is automatically fixable using the --fix flag on the command line. + <p>Sometimes in the course of editing files, you can end up with extra whitespace at the end of lines. These whitespace differences can be picked up by source control systems and flagged as diffs, causing frustration for developers. While this extra whitespace causes no functional issues, many code conventions require that trailing spaces be removed before checkin. Fixable: This rule is automatically fixable using the –fix flag on the command line.</p> + + + + Major + + { + "skipBlankLines": false, + "ignoreComments": false + } + + + + + + + + false + false + no-underscore-dangle + Stylistic Issues + + true + no-underscore-dangle + As far as naming conventions for identifiers go, dangling underscores may be the most polarizing in JavaScript. Dangling underscores are underscores at either the beginning or end of an identifier, such as: There is actually a long history of using dangling underscores to indicate "private" members of objects in JavaScript (though JavaScript doesn't have truly private members, this convention served as a warning). This began with SpiderMonkey adding nonstandard methods such as __defineGetter__(). The intent with the underscores was to make it obvious that this method was special in some way. Since that time, using a single underscore prefix has become popular as a way to indicate "private" members of objects. Whether or not you choose to allow dangling underscores in identifiers is purely a convention and has no effect on performance, readability, or complexity. It's purely a preference. + <p>As far as naming conventions for identifiers go, dangling underscores may be the most polarizing in JavaScript. Dangling underscores are underscores at either the beginning or end of an identifier, such as: There is actually a long history of using dangling underscores to indicate “private” members of objects in JavaScript (though JavaScript doesn’t have truly private members, this convention served as a warning). This began with SpiderMonkey adding nonstandard methods such as <strong>defineGetter</strong>(). The intent with the underscores was to make it obvious that this method was special in some way. Since that time, using a single underscore prefix has become popular as a way to indicate “private” members of objects. Whether or not you choose to allow dangling underscores in identifiers is purely a convention and has no effect on performance, readability, or complexity. It’s purely a preference.</p> + + + + Major + { "allow": [] } + + + + + + + false + false + no-unneeded-ternary + Stylistic Issues + + true + no-unneeded-ternary + It's a common mistake in JavaScript to use a conditional expression to select between two Boolean values instead of using ! to convert the test to a Boolean. Here are some examples: This rule disallows the use of 'Boolean' literals inside conditional expressions. Another common mistake is using a single variable as both the conditional test and the consequent. In such cases, the logical OR can be used to provide the same functionality. Here is an example: This rule disallows the conditional expression as a default assignment pattern when the defaultAssignment option is set to false. + <p>It’s a common mistake in JavaScript to use a conditional expression to select between two Boolean values instead of using ! to convert the test to a Boolean. Here are some examples: This rule disallows the use of ‘Boolean’ literals inside conditional expressions. Another common mistake is using a single variable as both the conditional test and the consequent. In such cases, the logical OR can be used to provide the same functionality. Here is an example: This rule disallows the conditional expression as a default assignment pattern when the defaultAssignment option is set to false.</p> + + + + Major + + { + "defaultAssignment": true + } + + + + + + + + false + false + no-whitespace-before-property + Stylistic Issues + + true + no-whitespace-before-property + JavaScript allows whitespace between objects and their properties. However, inconsistent spacing can make code harder to read and can lead to errors. + <p>JavaScript allows whitespace between objects and their properties. However, inconsistent spacing can make code harder to read and can lead to errors.</p> + + + + Major + + + + + + + false + false + nonblock-statement-body-position + Stylistic Issues + + true + nonblock-statement-body-position + When writing if, else, while, do-while, and for statements, the body can be a single statement instead of a block. It can be useful to enforce a consistent location for these single statements. + <p>When writing if, else, while, do-while, and for statements, the body can be a single statement instead of a block. It can be useful to enforce a consistent location for these single statements.</p> + + + + Major + "beside" + + + + + + + false + false + object-curly-newline + Stylistic Issues + + true + object-curly-newline + A number of style guides require or disallow line breaks inside of object braces and other tokens. + <p>A number of style guides require or disallow line breaks inside of object braces and other tokens.</p> + + + + Major + { "multiline": true } + + + + + + + false + false + object-curly-spacing + Stylistic Issues + + true + object-curly-spacing + While formatting preferences are very personal, a number of style guides require or disallow spaces between curly braces. + <p>While formatting preferences are very personal, a number of style guides require or disallow spaces between curly braces.</p> + + + + Major + "never" + + + + + + + false + false + object-curly-spacing + Stylistic Issues + + true + object-curly-spacing + This rule permits you to restrict the locations of property specifications in object literals. You may prohibit any part of any property specification from appearing on the same line as any part of any other property specification. You may make this prohibition absolute, or, by invoking an object option, you may allow an exception, permitting an object literal to have all parts of all of its property specifications on a single line. + <p>This rule permits you to restrict the locations of property specifications in object literals. You may prohibit any part of any property specification from appearing on the same line as any part of any other property specification. You may make this prohibition absolute, or, by invoking an object option, you may allow an exception, permitting an object literal to have all parts of all of its property specifications on a single line.</p> + + + + Major + + + + + + + false + false + one-var + Stylistic Issues + + true + one-var + Variables can be declared at any point in JavaScript code using var, let, or const. There are many styles and preferences related to the declaration of variables, and one of those is deciding on how many variable declarations should be allowed in a single function. There are two schools of thought in this regard: For instance: The single-declaration school of thought is based in pre-ECMAScript 6 behaviors, where there was no such thing as block scope, only function scope. Since all var statements are hoisted to the top of the function anyway, some believe that declaring all variables in a single declaration at the top of the function removes confusion around scoping rules. + <p>Variables can be declared at any point in JavaScript code using var, let, or const. There are many styles and preferences related to the declaration of variables, and one of those is deciding on how many variable declarations should be allowed in a single function. There are two schools of thought in this regard: For instance: The single-declaration school of thought is based in pre-ECMAScript 6 behaviors, where there was no such thing as block scope, only function scope. Since all var statements are hoisted to the top of the function anyway, some believe that declaring all variables in a single declaration at the top of the function removes confusion around scoping rules.</p> + + + + Major + "always" + + + + + + + false + false + one-var-declaration-per-line + Stylistic Issues + + true + one-var-declaration-per-lines + Some developers declare multiple var statements on the same line, others prefer to declare one var per line. Keeping to one of these styles across a project’s codebase can help with maintaining code consistency. + <p>Some developers declare multiple var statements on the same line, others prefer to declare one var per line. Keeping to one of these styles across a project’s codebase can help with maintaining code consistency.</p> + + + + Major + "initializations" + + + + + + + false + false + operator-assignment + Stylistic Issues + + true + operator-assignment + JavaScript provides shorthand operators that combine variable assignment and some simple mathematical operations. For example, x = x + 4 can be shortened to x += 4. The supported shorthand forms are as follows: + <p>JavaScript provides shorthand operators that combine variable assignment and some simple mathematical operations. For example, x = x + 4 can be shortened to x += 4. The supported shorthand forms are as follows:</p> + + + + Major + "always" + + + + + + + false + false + operator-linebreak + Stylistic Issues + + true + operator-linebreak + When a statement is too long to fit on a single line, line breaks are generally inserted next to the operators separating expressions. The first style coming to mind would be to place the operator at the end of the line, following the english punctuation rules. Some developers find that placing operators at the beginning of the line makes the code more readable. + <p>When a statement is too long to fit on a single line, line breaks are generally inserted next to the operators separating expressions. The first style coming to mind would be to place the operator at the end of the line, following the english punctuation rules. Some developers find that placing operators at the beginning of the line makes the code more readable.</p> + + + + Major + + + + + + + + false + false + padded-blocks + Stylistic Issues + + true + padded-blocks + Some style guides require block statements to start and end with blank lines. The goal is to improve readability by visually separating the block content and the surrounding code. Since it's good to have a consistent code style, you should either always write padded blocks or never do it. + <p>Some style guides require block statements to start and end with blank lines. The goal is to improve readability by visually separating the block content and the surrounding code. Since it’s good to have a consistent code style, you should either always write padded blocks or never do it.</p> + + + + Major + "always" + + + + + + + false + false + padding-line-between-statements + Stylistic Issues + + true + padding-line-between-statements + This rule requires or disallows blank lines between the given 2 kinds of statements. Properly blank lines help developers to understand the code. For example, the following configuration requires a blank line between a variable declaration and a return statement. + <p>This rule requires or disallows blank lines between the given 2 kinds of statements. Properly blank lines help developers to understand the code. For example, the following configuration requires a blank line between a variable declaration and a return statement.</p> + + + + Major + + + + + + + false + false + quote-props + Stylistic Issues + + true + quote-props + Object literal property names can be defined in two ways: using literals or using strings. For example, these two objects are equivalent: In many cases, it doesn't matter if you choose to use an identifier instead of a string or vice-versa. Even so, you might decide to enforce a consistent style in your code. There are, however, some occasions when you must use quotes: Another example where quotes do matter is when using numeric literals as property keys: This may look alright at first sight, but this code in fact throws a syntax error in ECMAScript 5 strict mode. This happens because 1e2 and 100 are coerced into strings before getting used as the property name. Both String(1e2) and String(100) happen to be equal to "100", which causes the "Duplicate data property in object literal not allowed in strict mode" error. Issues like that can be tricky to debug, so some prefer to require quotes around all property names. + <p>Object literal property names can be defined in two ways: using literals or using strings. For example, these two objects are equivalent: In many cases, it doesn’t matter if you choose to use an identifier instead of a string or vice-versa. Even so, you might decide to enforce a consistent style in your code. There are, however, some occasions when you must use quotes: Another example where quotes do matter is when using numeric literals as property keys: This may look alright at first sight, but this code in fact throws a syntax error in ECMAScript 5 strict mode. This happens because 1e2 and 100 are coerced into strings before getting used as the property name. Both String(1e2) and String(100) happen to be equal to “100”, which causes the “Duplicate data property in object literal not allowed in strict mode” error. Issues like that can be tricky to debug, so some prefer to require quotes around all property names.</p> + + + + Major + "always" + + + + + + + false + false + quotes + Stylistic Issues + + true + quotes + JavaScript allows you to define strings in one of three ways: double quotes, single quotes, and backticks (as of ECMAScript 6). For example: Each of these lines creates a string and, in some cases, can be used interchangeably. The choice of how to define strings in a codebase is a stylistic one outside of template literals (which allow embedded of expressions to be interpreted). Many codebases require strings to be defined in a consistent manner. + <p>JavaScript allows you to define strings in one of three ways: double quotes, single quotes, and backticks (as of ECMAScript 6). For example: Each of these lines creates a string and, in some cases, can be used interchangeably. The choice of how to define strings in a codebase is a stylistic one outside of template literals (which allow embedded of expressions to be interpreted). Many codebases require strings to be defined in a consistent manner.</p> + + + + Major + "double" + + + + + + + false + false + require-jsdoc + Stylistic Issues + + true + require-jsdoc + JSDoc is a JavaScript API documentation generator. It uses specially-formatted comments inside of code to generate API documentation automatically. For example, this is what a JSDoc comment looks like for a function: Some style guides require JSDoc comments for all functions as a way of explaining function behavior. + <p>JSDoc is a JavaScript API documentation generator. It uses specially-formatted comments inside of code to generate API documentation automatically. For example, this is what a JSDoc comment looks like for a function: Some style guides require JSDoc comments for all functions as a way of explaining function behavior.</p> + + + + Major + + { + "require": { + "FunctionDeclaration": true, + "MethodDefinition": false, + "ClassDeclaration": false, + "ArrowFunctionExpression": false, + "FunctionExpression": false + } + } + + + + + + + + false + false + semi + Stylistic Issues + + true + semi + JavaScript is unique amongst the C-like languages in that it doesn't require semicolons at the end of each statement. In many cases, the JavaScript engine can determine that a semicolon should be in a certain spot and will automatically add it. This feature is known as automatic semicolon insertion (ASI) and is considered one of the more controversial features of JavaScript. For example, the following lines are both valid: On the first line, the JavaScript engine will automatically insert a semicolon, so this is not considered a syntax error. The JavaScript engine still knows how to interpret the line and knows that the line end indicates the end of the statement. In the debate over ASI, there are generally two schools of thought. The first is that we should treat ASI as if it didn't exist and always include semicolons manually. The rationale is that it's easier to always include semicolons than to try to remember when they are or are not required, and thus decreases the possibility of introducing an error. However, the ASI mechanism can sometimes be tricky to people who are using semicolons. For example, consider this code: This may look like a return statement that returns an object literal, however, the JavaScript engine will interpret this code as: Effectively, a semicolon is inserted after the return statement, causing the code below it (a labeled literal inside a block) to be unreachable. This rule and the no-unreachable rule will protect your code from such cases. On the other side of the argument are those who says that since semicolons are inserted automatically, they are optional and do not need to be inserted manually. However, the ASI mechanism can also be tricky to people who don't use semicolons. For example, consider this code: In this example, a semicolon will not be inserted after the first line, causing a run-time error (because an empty object is called as if it's a function). The no-unexpected-multiline rule can protect your code from such cases. Although ASI allows for more freedom over your coding style, it can also make your code behave in an unexpected way, whether you use semicolons or not. Therefore, it is best to know when ASI takes place and when it does not, and have ESLint protect your code from these potentially unexpected cases. In short, as once described by Isaac Schlueter, a \n character always ends a statement (just like a semicolon) unless one of the following is true: + <p>JavaScript is unique amongst the C-like languages in that it doesn’t require semicolons at the end of each statement. In many cases, the JavaScript engine can determine that a semicolon should be in a certain spot and will automatically add it. This feature is known as automatic semicolon insertion (ASI) and is considered one of the more controversial features of JavaScript. For example, the following lines are both valid: On the first line, the JavaScript engine will automatically insert a semicolon, so this is not considered a syntax error. The JavaScript engine still knows how to interpret the line and knows that the line end indicates the end of the statement. In the debate over ASI, there are generally two schools of thought. The first is that we should treat ASI as if it didn’t exist and always include semicolons manually. The rationale is that it’s easier to always include semicolons than to try to remember when they are or are not required, and thus decreases the possibility of introducing an error. However, the ASI mechanism can sometimes be tricky to people who are using semicolons. For example, consider this code: This may look like a return statement that returns an object literal, however, the JavaScript engine will interpret this code as: Effectively, a semicolon is inserted after the return statement, causing the code below it (a labeled literal inside a block) to be unreachable. This rule and the no-unreachable rule will protect your code from such cases. On the other side of the argument are those who says that since semicolons are inserted automatically, they are optional and do not need to be inserted manually. However, the ASI mechanism can also be tricky to people who don’t use semicolons. For example, consider this code: In this example, a semicolon will not be inserted after the first line, causing a run-time error (because an empty object is called as if it’s a function). The no-unexpected-multiline rule can protect your code from such cases. Although ASI allows for more freedom over your coding style, it can also make your code behave in an unexpected way, whether you use semicolons or not. Therefore, it is best to know when ASI takes place and when it does not, and have ESLint protect your code from these potentially unexpected cases. In short, as once described by Isaac Schlueter, a character always ends a statement (just like a semicolon) unless one of the following is true:</p> + + + + Major + "always" + + + + + + + false + false + semi-spacing + Stylistic Issues + + true + semi-spacing + JavaScript allows you to place unnecessary spaces before or after a semicolon. Disallowing or enforcing space around a semicolon can improve the readability of your program. + <p>JavaScript allows you to place unnecessary spaces before or after a semicolon. Disallowing or enforcing space around a semicolon can improve the readability of your program.</p> + + + + Major + + { + "before": false, + "after": true + } + + + + + + + + false + false + semi-style + Stylistic Issues + + true + semi-style + Generally, semicolons are at the end of lines. However, in semicolon-less style, semicolons are at the beginning of lines. This rule enforces that semicolons are at the configured location. + <p>Generally, semicolons are at the end of lines. However, in semicolon-less style, semicolons are at the beginning of lines. This rule enforces that semicolons are at the configured location.</p> + + + + Major + "last" + + + + + + + false + false + sort-keys + Stylistic Issues + + true + sort-keys + This rule checks all property definitions of object expressions and verifies that all variables are sorted alphabetically. + <p>This rule checks all property definitions of object expressions and verifies that all variables are sorted alphabetically.</p> + + + + Major + "asc" + + + + + + + false + false + sort-vars + Stylistic Issues + + true + sort-vars + When declaring multiple variables within the same block, some developers prefer to sort variable names alphabetically to be able to find necessary variable easier at the later time. Others feel that it adds complexity and becomes burden to maintain. + <p>When declaring multiple variables within the same block, some developers prefer to sort variable names alphabetically to be able to find necessary variable easier at the later time. Others feel that it adds complexity and becomes burden to maintain.</p> + + + + Major + + { + "ignoreCase": true + } + + + + + + + + false + false + space-before-blocks + Stylistic Issues + + true + space-before-blocks + Consistency is an important part of any style guide. While it is a personal preference where to put the opening brace of blocks, it should be consistent across a whole project. Having an inconsistent style distracts the reader from seeing the important parts of the code. Fixable: This rule is automatically fixable using the --fix flag on the command line. + <p>Consistency is an important part of any style guide. While it is a personal preference where to put the opening brace of blocks, it should be consistent across a whole project. Having an inconsistent style distracts the reader from seeing the important parts of the code. Fixable: This rule is automatically fixable using the –fix flag on the command line.</p> + + + + Major + "always" + + + + + + + false + false + space-before-function-paren + Stylistic Issues + + true + space-before-function-paren + When formatting a function, whitespace is allowed between the function name or function keyword and the opening paren. Named functions also require a space between the function keyword and the function name, but anonymous functions require no whitespace. For example: Style guides may require a space after the function keyword for anonymous functions, while others specify no whitespace. Similarly, the space after a function name may or may not be required. Fixable: This rule is automatically fixable using the --fix flag on the command line. + <p>When formatting a function, whitespace is allowed between the function name or function keyword and the opening paren. Named functions also require a space between the function keyword and the function name, but anonymous functions require no whitespace. For example: Style guides may require a space after the function keyword for anonymous functions, while others specify no whitespace. Similarly, the space after a function name may or may not be required. Fixable: This rule is automatically fixable using the –fix flag on the command line.</p> + + + + Major + "always" + + + + + + + false + false + space-in-parens + Stylistic Issues + + true + space-in-parens + Some style guides require or disallow spaces inside of parentheses: + <p>Some style guides require or disallow spaces inside of parentheses:</p> + + + + Major + "never" + + + + + + + false + false + space-infix-ops + Stylistic Issues + + true + space-infix-ops + While formatting preferences are very personal, a number of style guides require spaces around operators, such as: The proponents of these extra spaces believe it make the code easier to read and can more easily highlight potential errors, such as: While this is valid JavaScript syntax, it is hard to determine what the author intended. Fixable: This rule is automatically fixable using the --fix flag on the command line. + <p>While formatting preferences are very personal, a number of style guides require spaces around operators, such as: The proponents of these extra spaces believe it make the code easier to read and can more easily highlight potential errors, such as: While this is valid JavaScript syntax, it is hard to determine what the author intended. Fixable: This rule is automatically fixable using the –fix flag on the command line.</p> + + + + Major + + { + "int32Hint": false + } + + + + + + + false + false + space-unary-ops + Stylistic Issues + + true + space-unary-ops + Some styleguides require or disallow spaces before or after unary operators. This is mainly a stylistic issue, however, some JavaScript expressions can be written without spacing which makes it harder to read and maintain. Fixable: This rule is automatically fixable using the --fix flag on the command line. + <p>Some styleguides require or disallow spaces before or after unary operators. This is mainly a stylistic issue, however, some JavaScript expressions can be written without spacing which makes it harder to read and maintain. Fixable: This rule is automatically fixable using the –fix flag on the command line.</p> + + + + Major + + { + "words": true, + "nonwords": false + } + + + + + + + + false + false + spaced-comment + Stylistic Issues + + true + spaced-comment + Some style guides require or disallow a whitespace immediately after the initial // or /* of a comment. Whitespace after the // or /* makes it easier to read text in comments. On the other hand, commenting out code is easier without having to put a whitespace right after the // or /*. + <p>Some style guides require or disallow a whitespace immediately after the initial // or /* of a comment. Whitespace after the // or /* makes it easier to read text in comments. On the other hand, commenting out code is easier without having to put a whitespace right after the // or /*.</p> + + + + Major + "always" + + + + + + + false + false + switch-colon-spacing + Stylistic Issues + + true + switch-colon-spacing + Spacing around colons improves readability of case/default clauses. + <p>Spacing around colons improves readability of case/default clauses.</p> + + + + Major + + { + "after": true, + "before": false + } + + + + + + + + false + false + template-tag-spacing + Stylistic Issues + + true + template-tag-spacing + This rule aims to maintain consistency around the spacing between template tag functions and their template literals. + <p>This rule aims to maintain consistency around the spacing between template tag functions and their template literals.</p> + + + + Major + + "never" + + + + + + + + false + false + unicode-bom + Stylistic Issues + + true + unicode-bom + The Unicode Byte Order Mark (BOM) is used to specify whether code units are big endian or little endian. That is, whether the most significant or least significant bytes come first. UTF-8 does not require a BOM because byte ordering does not matter when characters are a single byte. Since UTF-8 is the dominant encoding of the web, we make "never" the default option. + <p>The Unicode Byte Order Mark (BOM) is used to specify whether code units are big endian or little endian. That is, whether the most significant or least significant bytes come first. UTF-8 does not require a BOM because byte ordering does not matter when characters are a single byte. Since UTF-8 is the dominant encoding of the web, we make "never" the default option.</p> + + + + Major + + "never" + + + + + + + + false + false + wrap-regex + Stylistic Issues + + true + wrap-regex + When a regular expression is used in certain situations, it can end up looking like a division operator. For example: + <p>When a regular expression is used in certain situations, it can end up looking like a division operator. For example:</p> + + + + Major + + + + + + + + + + + + + + + + false + false + arrow-body-style + ECMAScript 6 + + true + arrow-body-style + Arrow functions can omit braces when there is a single statement in the body. This rule enforces the consistent use of braces in arrow functions. Additionally, this rule specifically warns against a possible developer error when the intention is to return an empty object literal but creates an empty block instead, returning undefined. + <p>Arrow functions can omit braces when there is a single statement in the body. This rule enforces the consistent use of braces in arrow functions. Additionally, this rule specifically warns against a possible developer error when the intention is to return an empty object literal but creates an empty block instead, returning undefined.</p></p> + + + + Major + "as-needed" + + + + + + + false + false + arrow-parens + ECMAScript 6 + + true + arrow-parens + Arrow functions can omit parentheses when they have exactly one parameter. In all other cases the parameter(s) must be wrapped in parentheses. This rule enforces the consistent use of parentheses in arrow functions. + <p>Arrow functions can omit parentheses when they have exactly one parameter. In all other cases the parameter(s) must be wrapped in parentheses. This rule enforces the consistent use of parentheses in arrow functions.</p></p> + + + + Major + "always" + + + + + + + false + false + arrow-spacing + ECMAScript 6 + + true + arrow-spacing + This rule normalize style of spacing before/after an arrow function's arrow(=>). Fixable: This rule is automatically fixable using the --fix flag on the command line. + <p>This rule normalize style of spacing before/after an arrow function’s arrow(=&gt;). Fixable: This rule is automatically fixable using the –fix flag on the command line.</p></p> + + + + Major + {"before": true, "after": true} + + + + + + + true + false + constructor-super + ECMAScript 6 + + true + constructor-super + Constructors of derived classes must call super(). Constructors of non derived classes must not call super(). If this is not observed, the javascript engine will raise a runtime error. This rule checks whether or not there is a valid super() call. + <p>Constructors of derived classes must call super(). Constructors of non derived classes must not call super(). If this is not observed, the javascript engine will raise a runtime error. This rule checks whether or not there is a valid super() call.</p> + + + + Major + + + + + + + false + false + generator-star-spacing + ECMAScript 6 + + true + generator-star-spacing + Generators are a new type of function in ECMAScript 6 that can return multiple values over time. These special functions are indicated by placing an * after the function keyword. Here is an example of a generator function: This is also valid: This is valid as well: To keep a sense of consistency when using generators this rule enforces a single position for the *. Fixable: This rule is automatically fixable using the --fix flag on the command line. + <p>Generators are a new type of function in ECMAScript 6 that can return multiple values over time. These special functions are indicated by placing an * after the function keyword. Here is an example of a generator function: This is also valid: This is valid as well: To keep a sense of consistency when using generators this rule enforces a single position for the *. Fixable: This rule is automatically fixable using the –fix flag on the command line.</p></p> + + + + Major + {"before": true, "after": false} + + + + + + + false + false + no-confusing-arrow + ECMAScript 6 + + true + no-confusing-arrow + Arrow functions (=>) are similar in syntax to some comparison operators (>, <, <=, and >=). This rule warns against using the arrow function syntax in places where it could be confused with a comparison operator. Even if the arguments of the arrow function are wrapped with parens, this rule still warns about it unless allowParens is set to true. + <p>Arrow functions (=>) are similar in syntax to some comparison operators (>, <, <=, and >=). This rule warns against using the arrow function syntax in places where it could be confused with a comparison operator. Even if the arguments of the arrow function are wrapped with parens, this rule still warns about it unless allowParens is set to true.</p></p> + + + + Major + {"allowParens": false} + + + + + + + true + false + no-class-assign + ECMAScript 6 + + true + no-class-assign + ClassDeclaration creates a variable, and we can modify the variable. But the modification is a mistake in most cases. + <p>ClassDeclaration creates a variable, and we can modify the variable. But the modification is a mistake in most cases.</p> + + + + Major + + + + + + + true + false + no-const-assign + ECMAScript 6 + + true + no-const-assign + We cannot modify variables that are declared using const keyword. It will raise a runtime error. Under non ES2015 environment, it might be ignored merely. + <p>We cannot modify variables that are declared using const keyword. It will raise a runtime error. Under non ES2015 environment, it might be ignored merely.</p></p> + + + + Major + + + + + + + false + false + no-dupe-class-members + ECMAScript 6 + + true + no-dupe-class-members + If there are declarations of the same name in class members, the last declaration overwrites other declarations silently. It can cause unexpected behaviors. + <p>If there are declarations of the same name in class members, the last declaration overwrites other declarations silently. It can cause unexpected behaviors.</p></p> + + + + Major + + + + + + + false + false + no-duplicate-imports + ECMAScript 6 + + true + no-duplicate-imports + Using a single import statement per module will make the code clearer because you can see everything being imported from that module on one line. In the following example the module import on line 1 is repeated on line 3. These can be combined to make the list of imports more succinct. + <p>Using a single import statement per module will make the code clearer because you can see everything being imported from that module on one line. In the following example the module import on line 1 is repeated on line 3. These can be combined to make the list of imports more succinct.</p></p> + + + + Major + {"includeExports": false} + + + + + + + true + false + no-new-symbol + ECMAScript 6 + + true + no-new-symbol + Using a single import statement per module will make the code clearer because you can see everything being imported from that module on one line. In the following example the module import on line 1 is repeated on line 3. These can be combined to make the list of imports more succinct. + <p>Using a single import statement per module will make the code clearer because you can see everything being imported from that module on one line. In the following example the module import on line 1 is repeated on line 3. These can be combined to make the list of imports more succinct.</p></p> + + + + Major + + + + + + + false + false + no-restricted-imports + ECMAScript 6 + + true + no-restricted-imports + Imports are an ES6/ES2015 standard for making the functionality of other modules available in your current module. In CommonJS this is implemented through the require() call which makes this ESLint rule roughly equivalent to its CommonJS counterpart no-restricted-modules.<br />Why would you want to restrict imports?<br /><br />Some imports might not make sense in a particular environment. For example, Node.js’ fs module would not make sense in an environment that didn’t have a file system.<br />Some modules provide similar or identical functionality, think lodash and underscore. Your project may have standardized on a module. You want to make sure that the other alternatives are not being used as this would unnecessarily bloat the project and provide a higher maintenance cost of two dependencies when one would suffice. + <p>Imports are an ES6/ES2015 standard for making the functionality of other modules available in your current module. In CommonJS this is implemented through the require() call which makes this ESLint rule roughly equivalent to its CommonJS counterpart no-restricted-modules.<br />Why would you want to restrict imports?<br /><br />Some imports might not make sense in a particular environment. For example, Node.js’ fs module would not make sense in an environment that didn’t have a file system.<br />Some modules provide similar or identical functionality, think lodash and underscore. Your project may have standardized on a module. You want to make sure that the other alternatives are not being used as this would unnecessarily bloat the project and provide a higher maintenance cost of two dependencies when one would suffice.</p></p> + + + + Major + {"paths": ["exampleImport1", "exampleImport2"]} + + + + + + + true + false + no-this-before-super + ECMAScript 6 + + true + no-this-before-super + In the constructor of derived classes, if this/super are used before super() calls, it raises a reference error. This rule checks this/super keywords in constructors, then reports those that are before super(). + <p>In the constructor of derived classes, if this/super are used before super() calls, it raises a reference error. This rule checks this/super keywords in constructors, then reports those that are before super().</p></p> + + + + Major + + + + + + + false + false + no-useless-computed-key + ECMAScript 6 + + true + no-useless-computed-key + The --fix option on the command line can automatically fix some of the problems reported by this rule.<br /><br />It’s unnecessary to use computed properties with literals such as:<br />var foo = {["a"]: "b"};<br />The code can be rewritten as:<br />var foo = {"a": "b"}; + <p>The --fix option on the command line can automatically fix some of the problems reported by this rule.<br /><br />It’s unnecessary to use computed properties with literals such as:<br />var foo = {["a"]: "b"};<br />The code can be rewritten as:<br />var foo = {"a": "b"};</p></p> + + + + Major + + + + + + + false + false + no-useless-rename + ECMAScript 6 + + true + no-useless-rename + ES2015 provides a default class constructor if one is not specified. As such, it is unnecessary to provide an empty constructor or one that simply delegates into its parent class. + <p>ES2015 provides a default class constructor if one is not specified. As such, it is unnecessary to provide an empty constructor or one that simply delegates into its parent class</p></p> + + + + Major + { + "ignoreDestructing": false, + "ignoreImport": false, + "ignoreExport": false + } + + + + + + + false + false + no-var + ECMAScript 6 + + true + no-var + ECMAScript 6 allows programmers to create variables with block scope instead of function scope using the let and const keywords. Block scope is common in many other programming languages and helps programmers avoid mistakes such as: + <p>ECMAScript 6 allows programmers to create variables with block scope instead of function scope using the let and const keywords. Block scope is common in many other programming languages and helps programmers avoid mistakes such as:</p></p> + + + + Major + + + + + + + false + false + object-shorthand + ECMAScript 6 + + true + object-shorthand + EcmaScript 6 provides a concise form for defining object literal methods and properties. This syntax can make defining complex object literals much cleaner. Here are a few common examples using the ES5 syntax: Now here are ES6 equivalents: + <p>EcmaScript 6 provides a concise form for defining object literal methods and properties. This syntax can make defining complex object literals much cleaner. Here are a few common examples using the ES5 syntax: Now here are ES6 equivalents:</p></p> + + + + Major + "always" + + + + + + + false + false + prefer-arrow-callback + ECMAScript 6 + + true + prefer-arrow-callback + Arrow functions are suited to callbacks, because: + <p>Arrow functions are suited to callbacks, because:</p></p> + + + + Major + {"allowNamedFunction": false, "allowUnboundThis": true} + + + + + + + false + false + prefer-const + ECMAScript 6 + + true + prefer-const + If a variable is never modified, using the const declaration is better. const declaration tells readers, "this variable is never modified," reducing cognitive load and improving maintainability. + <p>If a variable is never modified, using the const declaration is better. const declaration tells readers, “this variable is never modified,” reducing cognitive load and improving maintainability.</p></p> + + + + Major + { + "destructing": "any", + "ignoreReadBeforeAssign": false + } + + + + + + + false + false + prefer-destructing + ECMAScript 6 + + true + prefer-destructing + With JavaScript ES6, a new syntax was added for creating variables from an array index or object property, called destructuring. This rule enforces usage of destructuring instead of accessing a property through a member expression. + <p>With JavaScript ES6, a new syntax was added for creating variables from an array index or object property, called destructuring. This rule enforces usage of destructuring instead of accessing a property through a member expression.</p></p> + + + + Major + + [{ + "array": true, + "object": true + }, { + "enforceForRenamedProperties": false + }] + + + + + + + + false + false + prefer-numeric-literals + ECMAScript 6 + + true + prefer-numeric-literals + The parseInt() and Number.parseInt() functions can be used to turn binary, octal, and hexadecimal strings into integers. As binary, octal, and hexadecimal literals are supported in ES6, this rule encourages use of those numeric literals instead of parseInt() or Number.parseInt() + <p>The parseInt() and Number.parseInt() functions can be used to turn binary, octal, and hexadecimal strings into integers. As binary, octal, and hexadecimal literals are supported in ES6, this rule encourages use of those numeric literals instead of parseInt() or Number.parseInt()</p></p> + + + + Major + + + + + + + false + false + prefer-rest-params + ECMAScript 6 + + true + prefer-rest-params + There are rest parameters in ES2015. We can use that feature for variadic functions instead of the arguments variable. Arguments does not have methods of Array.prototype, so it’s a bit of an inconvenience. + <p>There are rest parameters in ES2015. We can use that feature for variadic functions instead of the arguments variable. Arguments does not have methods of Array.prototype, so it’s a bit of an inconvenience.</p></p> + + + + Major + + + + + + + false + false + prefer-spread + ECMAScript 6 + + true + prefer-spread + Before ES2015, one must use Function.prototype.apply() to call variadic functions. In ES2015, one can use the spread operator to call variadic functions. + <p>Before ES2015, one must use Function.prototype.apply() to call variadic functions. In ES2015, one can use the spread operator to call variadic functions.</p></p> + + + + Major + + + + + + + false + false + prefer-template + ECMAScript 6 + + true + prefer-template + In ES2015 (ES6), we can use template literals instead of string concatenation. + <p>In ES2015 (ES6), we can use template literals instead of string concatenation.</p></p> + + + + Major + + + + + + + true + false + require-yield + ECMAScript 6 + + true + require-yield + This rule generates warnings for generator functions that do not have the yield keyword. + <p>This rule generates warnings for generator functions that do not have the yield keyword.</p></p> + + + + Major + + + + + + + false + false + rest-spread-spacing + ECMAScript 6 + + true + rest-spread-spacing + ES2015 introduced the rest and spread operators, which expand an iterable structure into its individual parts. Some examples of their usage are as follows. + <p>ES2015 introduced the rest and spread operators, which expand an iterable structure into its individual parts. Some examples of their usage are as follows.</p></p> + + + + Major + "never" + + + + + + + false + false + sort-imports + ECMAScript 6 + + true + sort-imports + The import statement is used to import members (functions, objects or primitives) that have been exported from an external module. Using a specific member syntax: + <p>The import statement is used to import members (functions, objects or primitives) that have been exported from an external module. Using a specific member syntax:</p></p> + + + + Major + { + "ignoreCase": false, + "ignoreMemberSort": false, + "memberSyntaxSortOrder": ["none", "all", "multiple", "single"] + } + + + + + + + false + false + symbol-description + ECMAScript 6 + + true + symbol-description + The Symbol function may have optional description. Using description promotes easier debugging: when a symbol is logged the description is used. + <p>The Symbol function may have optional description. Using description promotes easier debugging: when a symbol is logged the description is used.</p></p> + + + + Major + + + + + + + false + false + template-curly-spacing + ECMAScript 6 + + true + template-curly-spacing + We can embed expressions in template strings with using a pair of ${ and }. This rule can force usage of spacing within the curly brace pair according to style guides. + <p>We can embed expressions in template strings with using a pair of ${ and }. This rule can force usage of spacing within the curly brace pair according to style guides.</p></p> + + + + Major + "never" + + + + + + + false + false + yield-star-spacing + ECMAScript 6 + + true + yield-star-spacing + This rule enforces spacing around the * in yield* expressions. To use this rule you either need to use the es6 environment or set ecmaVersion to 6 in parserOptions. + <p>This rule enforces spacing around the * in yield* expressions. To use this rule you either need to use the es6 environment or set ecmaVersion to 6 in parserOptions.</p></p> + + + + Major + {"before": true, "after": false} + + + + + + + + + + + + + + + + + + + + true + false + @typescript-eslint/adjacent-overload-signatures + TS Stylistic Issues + + true + adjacent-overload-signatures + Require that member overloads be consecutive. Grouping overloaded members together can improve readability of the code. + <p>This rule aims to standardize the way overloaded members are organized.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/lines-between-class-members + TS Stylistic Issues + + true + lines-between-class-members + Require or disallow an empty line between class members. This rule improves readability by enforcing lines between class members. It will not check empty lines before the first member and after the last member. This rule require or disallow an empty line between class members. + <p>This rule extends the base eslint/lines-between-class-members rule. It adds support for ignoring overload methods in a class.</p> + + + + Major + "always" + + + + + + + + + false + false + @typescript-eslint/brace-style + TS Stylistic Issues + + true + brace-style + Enforce consistent brace style for blocks. + <p>This rule extends the base eslint/brace-style rule. It adds support for enum, interface, namespace and module declarations.</p> + + + + Major + "1tbs" + + + + + + + + false + false + @typescript-eslint/indent + TS Stylistic Issues + + true + indent + Enforce consistent indentation. + <p>This rule extends the base eslint/indent rule. It adds support for TypeScript nodes.</p> + + + + Major + 2 + + + + + + + + false + false + @typescript-eslint/keyword-spacing + TS Stylistic Issues + + true + keyword-spacing + Enforce consistent spacing before and after keywords. + <p>This rule extends the base eslint/keyword-spacing rule. This version adds support for generic type parameters on function calls.</p> + + + + Major + { "before": true, "after": true, "overrides": {} } + + + + + + + + false + false + @typescript-eslint/no-array-constructor + TS Stylistic Issues + + true + no-array-constructor + Disallow generic Array constructors. + <p>This rule extends the base eslint/no-array-constructor rule. It adds support for the generically typed Array constructor.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/object-curly-spacing + TS Stylistic Issues + + true + object-curly-spacing + Enforce consistent spacing inside braces. + <p>This rule extends the base eslint/object-curly-spacing rule. It adds support for TypeScript's object types.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/padding-line-between-statements + TS Stylistic Issues + + true + padding-line-between-statements + Require or disallow padding lines between statements. + <p>This rule extends the base eslint/padding-line-between-statements rule. It adds support for TypeScript constructs such as interface and type.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/quotes + TS Stylistic Issues + + true + quotes + Enforce the consistent use of either backticks, double, or single quotes. + <p>This rule extends the base eslint/quotes rule. It adds support for TypeScript features which allow quoted names, but not backtick quoted names.</p> + + + + Major + "double" + + + + + + + + false + false + @typescript-eslint/semi + TS Stylistic Issues + + true + semi + Require or disallow semicolons instead of ASI. This rule enforces consistent use of semicolons after statements. + <p>This rule extends the base eslint/semi rule. It adds support for TypeScript features that require semicolons.</p> + + + + Major + "always" + + + + + + + + false + false + @typescript-eslint/space-before-function-paren + TS Stylistic Issues + + true + space-before-function-paren + Enforces consistent spacing before function parenthesis. + <p>This rule extends the base eslint/space-before-function-paren rule. It adds support for generic type parameters on function calls.</p> + + + + Major + "always" + + + + + + + + false + false + @typescript-eslint/space-infix-ops + TS Stylistic Issues + + true + space-infix-ops + This rule is aimed at ensuring there are spaces around infix operators. + <p>This rule extends the base eslint/space-infix-ops rule. It also add support for enum members.</p> + + + + Major + { "int32Hint": false } + + + + + + + + true + false + @typescript-eslint/array-type + TS Stylistic Issues + + true + array-type + Requires using either T[] for arrays. Using the same style for array definitions across your codebase makes it easier for your developers to read and understand the types. + <p>This rule aims to standardize usage of array types within your codebase.</p> + + + + Major + {"array-type": [true, "generic"]} + + + + + + + + false + false + @typescript-eslint/class-literal-property-style + TS Stylistic Issues + + true + class-literal-property-style + Ensures that literals on classes are exposed in a consistent style. When writing TypeScript applications, it's typically safe to store literal values on classes using fields with the readonly modifier to prevent them from being reassigned. When writing TypeScript libraries that could be used by JavaScript users however, it's typically safer to expose these literals using getters, since the readonly modifier is enforced at compile type. + <p>This rule aims to ensure that literals exposed by classes are done so consistently, in one of the two style described above. By default this rule prefers the fields style as it means JS doesn't have to setup and teardown a function closure. Note that this rule only checks for constant literal values (string, template string, number, bigint, boolean, regexp, null). It does not check objects or arrays, because a readonly field behaves differently to a getter in those cases. It also does not check functions, as it is a common pattern to use readonly fields with arrow function values as auto-bound methods. This is because these types can be mutated and carry with them more complex implications about their usage.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/consistent-indexed-object-style + TS Stylistic Issues + + true + consistent-indexed-object-style + Enforce or disallow the use of the record type. + <p>This rule enforces a consistent way to define records.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/consistent-type-assertions + TS Stylistic Issues + + true + consistent-type-assertions + Enforces consistent usage of type assertions. + <p>This rule aims to standardize the use of type assertion style across the codebase. Type assertions are also commonly referred as "type casting" in TypeScript (even though it is technically slightly different to what is understood by type casting in other languages), so you can think of type assertions and type casting referring to the same thing. It is essentially you saying to the TypeScript compiler, "in this case, I know better than you!".</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/member-delimiter-style + TS Stylistic Issues + + true + member-delimiter-style + Require a specific member delimiter style for interfaces and type literals. + <p>This rule aims to standardize the way interface and type literal members are delimited.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/member-ordering + TS Stylistic Issues + + true + member-ordering + Require a consistent member declaration order. A consistent ordering of fields, methods and constructors can make interfaces, type literals, classes and class expressions easier to read, navigate and edit. + <p>This rule aims to standardize the way class declarations, class expressions, interfaces and type literals are structured and ordered.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/method-signature-style + TS Stylistic Issues + + true + method-signature-style + Enforces using a particular method signature syntax. + <p>-</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/no-extraneous-class + TS Stylistic Issues + + true + no-extraneous-class + Forbids the use of classes as namespaces. This rule warns when a class is accidentally used as a namespace. + <p>Forbids the use of classes as namespaces. This rule warns when a class is accidentally used as a namespace.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/no-require-imports + TS Stylistic Issues + + true + no-require-imports + Disallows invocation of require(). + <p>Prefer the newer ES6-style imports over require().</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/no-var-requires + TS Stylistic Issues + + true + no-var-requires + Disallows the use of require statements except in import statements. In other words, the use of forms such as var foo = require("foo") are banned. Instead use ES6 style imports or import foo = require("foo") imports. + <p>-</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/type-annotation-spacing + TS Stylistic Issues + + true + type-annotation-spacing + Require consistent spacing around type annotations. + <p>This rule aims to enforce specific spacing patterns around type annotations and function types in type literals.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/typedef + TS Stylistic Issues + + true + typedef + Requires type annotations to exist. + <p>This rule can enforce type annotations in locations regardless of whether they're required. This is typically used to maintain consistency for element types that sometimes require them.</p> + + + + Major + + + + + + + true + false + @typescript-eslint/unified-signatures + TS Stylistic Issues + + true + unified-signatures + Warns for any two overloads that could be unified into one by using a union or an optional/rest parameter. + <p>This rule aims to keep the source code as maintainable as possible by reducing the amount of overloads.</p> + + + + Major + + + + + + + + + + + + + + + + + true + false + @typescript-eslint/no-extra-parens + TS Possible Errors + + true + no-extra-parens + Disallow unnecessary parentheses. + <p>This rule extends the base eslint/no-extra-parens rule. It adds support for TypeScript type assertions.</p> + + + + Major + "all" + + + + + + + + true + false + @typescript-eslint/no-extra-semi + TS Possible Errors + + true + no-extra-semi + Disallow unnecessary semicolons. + <p>This rule extends the base eslint/no-extra-semi rule. It adds support for class properties.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/comma-dangle + TS Possible Errors + + true + comma-dangle + Require or disallow trailing comma. + <p>This rule extends the base eslint/comma-dangle rule. It adds support for TypeScript syntax.</p> + + + + Major + { "arrays": "never","objects": "never","imports": "never","exports": "never","functions": "ignore","enums": "never","generics": "never","tuples": "never"} + + + + + + + + false + false + @typescript-eslint/func-call-spacing + TS Possible Errors + + true + func-call-spacing + Require or disallow spacing between function identifiers and their invocations. + <p>This rule extends the base eslint/func-call-spacing rule. It adds support for generic type parameters on function calls.</p> + + + + Major + "never" + + + + + + + + true + false + @typescript-eslint/no-dupe-class-members + TS Possible Errors + + true + no-dupe-class-members + Disallow duplicate class members. + <p>This rule extends the base eslint/no-dupe-class-members rule. It adds support for TypeScript's method overload definitions.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/no-duplicate-imports + TS Possible Errors + + true + no-duplicate-imports + Disallow duplicate imports. + <p>This rule extends the base eslint/no-duplicate-imports rule. This version adds support for type-only import and export.</p> + + + + Major + { "includeExports": false } + + + + + + + + false + false + @typescript-eslint/no-restricted-imports + TS Possible Errors + + true + no-restricted-imports + Disallow specified modules when loaded by import. + <p>This rule extends the base eslint/no-restricted-imports rule.</p> + + + + Major + { "paths": [ "exampleImport1", "exampleImport2" ] } + + + + + + + + false + false + @typescript-eslint/no-base-to-string + TS Possible Errors + + true + no-base-to-string + Requires that .toString() is only called on objects which provide useful information when stringified. + <p>This rule prevents accidentally defaulting to the base Object .toString() method.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/no-confusing-void-expression + TS Possible Errors + + true + no-confusing-void-expression + Requires expressions of type void to appear in statement position. + <p>This rule provides automatic fixes for most common cases.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/no-dynamic-delete + TS Possible Errors + + true + no-dynamic-delete + Disallow the delete operator with computed key expressions. + <p>Using the delete operator on keys that aren't runtime constants could be a sign that you're using the wrong data structures. Using Objects with added and removed keys can cause occasional edge case bugs, such as if a key is named "hasOwnProperty". Consider using a Map or Set if you’re storing collections of objects.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/no-empty-interface + TS Possible Errors + + true + no-empty-interface + Disallow the declaration of empty interfaces. An empty interface is equivalent to its supertype. If the interface does not implement a supertype, then the interface is equivalent to an empty object ({}). In both cases it can be omitted. + <p>This rule aims to ensure that only meaningful interfaces are declared in the code.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/no-floating-promises + TS Possible Errors + + true + no-floating-promises + Requires Promise-like values to be handled appropriately. This rule forbids usage of Promise-like values in statements without handling their errors appropriately. Unhandled promises can cause several issues, such as improperly sequenced operations, ignored Promise rejections and more. Valid ways of handling a Promise-valued statement include awaiting, returning, and either calling .then() with two arguments or .catch() with one argument. + <p>Requires Promise-like values to be handled appropriately. This rule forbids usage of Promise-like values in statements without handling their errors appropriately. Unhandled promises can cause several issues, such as improperly sequenced operations, ignored Promise rejections and more. Valid ways of handling a Promise-valued statement include awaiting, returning, and either calling .then() with two arguments or .catch() with one argument.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/no-for-in-array + TS Possible Errors + + true + no-for-in-array + Disallow iterating over an array with a for-in loop. + <p>A for-in loop (for (var k in o)) iterates over the properties of an Object. While it is legal to use for-in loops with array types, it is not common. for-in will iterate over the indices of the array as strings, omitting any "holes" in the array. More common is to use for-of, which iterates over the values of an array.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/no-implicit-any-catch + TS Possible Errors + + true + no-implicit-any-catch + TypeScript 4.0 added support for adding an explicit any or unknown type annotation on a catch clause variable. By default, TypeScript will type a catch clause variable as any, so explicitly annotating it as unknown can add a lot of safety to your codebase. The noImplicitAny flag in TypeScript does not cover this for backwards compatibility reasons. + <p>This rule requires an explicit type to be declared on a catch clause variable.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/no-misused-promises + TS Possible Errors + + true + no-misused-promises + Avoid using promises in places not designed to handle them. + <p>This rule forbids using promises in places where the TypeScript compiler allows them but they are not handled properly. These situations can often arise due to a missing await keyword or just a misunderstanding of the way async functions are handled/awaited.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/no-non-null-asserted-optional-chain + TS Possible Errors + + true + no-non-null-asserted-optional-chain + Disallows using a non-null assertion after an optional chain expression. + <p>Optional chain expressions are designed to return undefined if the optional property is nullish. Using non-null assertions after an optional chain expression is wrong, and introduces a serious type safety hole into your code.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/no-unsafe-argument + TS Possible Errors + + true + no-unsafe-argument + Disallows calling a function with an any type value. Despite your best intentions, the any type can sometimes leak into your codebase. Call a function with any typed argument are not checked at all by TypeScript, so it creates a potential safety hole, and source of bugs in your codebase. + <p>This rule disallows calling a function with any in its arguments, and it will disallow spreading any[]. This rule also disallows spreading a tuple type with one of its elements typed as any. This rule also compares the argument's type to the variable's type to ensure you don't pass an unsafe any in a generic position to a receiver that's expecting a specific type. For example, it will error if you assign Set any to an argument declared as Set string.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/no-unsafe-assignment + TS Possible Errors + + true + no-unsafe-assignment + Disallows assigning any to variables and properties. Despite your best intentions, the any type can sometimes leak into your codebase. Assigning an any typed value to a variable can be hard to pick up on, particularly if it leaks in from an external library. Operations on the variable will not be checked at all by TypeScript, so it creates a potential safety hole, and source of bugs in your codebase. + <p>This rule disallows assigning any to a variable, and assigning any[] to an array destructuring. This rule also compares the assigned type to the variable's type to ensure you don't assign an unsafe any in a generic position to a receiver that's expecting a specific type. For example, it will error if you assign Set any to a variable declared as Set string.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/no-unsafe-call + TS Possible Errors + + true + no-unsafe-call + Disallows calling an any type value. Despite your best intentions, the any type can sometimes leak into your codebase. The arguments to, and return value of calling an any typed variable are not checked at all by TypeScript, so it creates a potential safety hole, and source of bugs in your codebase. + <p>This rule disallows calling any variable that is typed as any.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/no-unsafe-member-access + TS Possible Errors + + true + no-unsafe-member-access + Disallows member access on any typed variables. Despite your best intentions, the any type can sometimes leak into your codebase. Member access on any typed variables is not checked at all by TypeScript, so it creates a potential safety hole, and source of bugs in your codebase. + <p>This rule disallows member access on any variable that is typed as any.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/no-unsafe-return + TS Possible Errors + + true + no-unsafe-return + Disallows returning any from a function. Despite your best intentions, the any type can sometimes leak into your codebase. Returned any typed values are not checked at all by TypeScript, so it creates a potential safety hole, and source of bugs in your codebase. + <p>This rule disallows returning any or any[] from a function. This rule also compares the return type to the function's declared/inferred return type to ensure you don't return an unsafe any in a generic position to a receiver that's expecting a specific type. For example, it will error if you return Set any from a function declared as returning Set string.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/non-nullable-type-assertion-style + TS Possible Errors + + true + non-nullable-type-assertion-style + Prefers a non-null assertion over explicit type cast when possible. + <p>This rule detects when an as cast is doing the same job as a ! would, and suggests fixing the code to be an !.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/prefer-as-const + TS Possible Errors + + true + prefer-as-const + Prefer usage of as const over literal type. + <p>This rule recommends usage of const assertion when type primitive value is equal to type.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/promise-function-async + TS Possible Errors + + true + promise-function-async + Requires any function or method that returns a Promise to be marked async. + <p>Requires any function or method that returns a Promise to be marked async.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/require-array-sort-compare + TS Possible Errors + + true + require-array-sort-compare + Requires Array#sort calls to always provide a compareFunction. + <p>This rule aims to ensure all calls of the native Array#sort method provide a compareFunction, while ignoring calls to user-defined sort methods.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/restrict-plus-operands + TS Possible Errors + + true + restrict-plus-operands + When adding two variables, operands must both be of type number or of type string. + <p>-</p> + + + + Major + + + + + + + + + + + + + + + + false + false + @typescript-eslint/dot-notation + TS Best Practices + + true + dot-notation + Enforce dot notation whenever possible. + <p>This rule extends the base eslint/dot-notation rule. It adds: Support for optionally ignoring computed private and/or protected member access andompatibility with TypeScript's noPropertyAccessFromIndexSignature option.</p> + + + + Major + { "allowKeywords": true } + + + + + + + + false + false + @typescript-eslint/no-empty-function + TS Best Practices + + true + no-empty-function + Disallow empty functions. + <p>This rule extends the base eslint/no-empty-function rule. It adds support for handling TypeScript specific code that would otherwise trigger the rule.</p> + + + + Major + { "allow": [] } + + + + + + + + false + false + @typescript-eslint/no-implied-eval + TS Best Practices + + true + no-implied-eval + Disallow the use of eval()-like methods. + <p>It's considered a good practice to avoid using eval(). There are security and performance implications involved with doing so, which is why many linters recommend disallowing eval(). However, there are some other ways to pass a string and have it interpreted as JavaScript code that have similar concerns.</p> + + + + Major + + + + + + + false + false + @typescript-eslint/no-invalid-this + TS Best Practices + + true + no-invalid-this + Disallow this keywords outside of classes or class-like objects. + <p>This rule extends the base eslint/no-invalid-this rule. It adds support for TypeScript's this parameters.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/no-loop-func + TS Best Practices + + true + no-loop-func + Disallow function declarations that contain unsafe references inside loop statements. + <p>This rule extends the base eslint/no-loop-func rule. It adds support for TypeScript types.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/no-magic-numbers + TS Best Practices + + true + no-magic-numbers + Disallow magic numbers. + <p>This rule extends the base eslint/no-magic-numbers rule. It adds support for: numeric literal types, enum members, and readonly class properties.</p> + + + + Major + { "ignore": [ ],"ignoreArrayIndexes": false,"enforceConst": false,"detectObjects": false } + + + + + + + + true + false + @typescript-eslint/no-redeclare + TS Best Practices + + true + no-redeclare + Disallow variable redeclaration. + <p>This rule extends the base eslint/no-redeclare rule. It adds support for TypeScript function overloads, and declaration merging.</p> + + + + Major + { "builtinGlobals": false } + + + + + + + + false + false + @typescript-eslint/no-throw-literal + TS Best Practices + + true + no-throw-literal + Disallow throwing literals as exceptions. It is considered good practice to only throw the Error object itself or an object using the Error object as base objects for user-defined exceptions. The fundamental benefit of Error objects is that they automatically keep track of where they were built and originated. + This rule restricts what can be thrown as an exception. When it was first created, it only prevented literals from being thrown (hence the name), but it has now been expanded to only allow expressions which have a possibility of being an Error object. + <p>This rule is aimed at maintaining consistency when throwing exception by disallowing to throw literals and other expressions which cannot possibly be an Error object.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/no-unused-expressions + TS Best Practices + + true + no-unused-expressions + Disallow unused expressions. + <p>This rule extends the base eslint/no-unused-expressions rule. It adds support for optional call expressions x?.(), and directive in module declarations.</p> + + + + Major + { "allowShortCircuit": false,"allowTernary": false,"allowTaggedTemplates": false } + + + + + + + + false + false + @typescript-eslint/require-await + TS Best Practices + + true + require-await + Disallow async functions which have no await expression. + <p>This rule extends the base eslint/require-await rule. It uses type information to add support for async functions that return a Promise.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/await-thenable + TS Best Practices + + true + await-thenable + Disallows awaiting a value that is not a Thenable. This rule disallows awaiting a value that is not a "Thenable" (an object which has then method, such as a Promise). While it is valid JavaScript to await a non-Promise-like value (it will resolve immediately), this pattern is often a programmer error, such as forgetting to add parenthesis to call a function that returns a Promise. + <p>-</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/ban-ts-comment + TS Best Practices + + true + ban-ts-comment + Bans @ts-directive comments from being used or requires descriptions after directive. TypeScript provides several directive comments that can be used to alter how it processes files. Using these to suppress TypeScript Compiler Errors reduces the effectiveness of TypeScript overall. + <p>This rule lets you set which directive comments you want to allow in your codebase. By default, only @ts-check is allowed, as it enables rather than suppresses errors.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/ban-tslint-comment + TS Best Practices + + true + ban-tslint-comment + Bans // tslint:rule-flag comments from being used. Useful when migrating from TSLint to ESLint. Once TSLint has been removed, this rule helps locate TSLint annotations + <p>-</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/ban-types + TS Best Practices + + true + ban-types + Bans specific types from being used. Some builtin types have aliases, some types are considered dangerous or harmful. It's often a good idea to ban certain types to help with consistency and safety. + <p>This rule bans specific types and can suggest alternatives. Note that it does not ban the corresponding runtime objects from being used.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/consistent-type-definitions + TS Best Practices + + true + consistent-type-definitions + Consistent with type definition either interface or type. + <p>-</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/consistent-type-imports + TS Best Practices + + true + consistent-type-imports + Enforces consistent usage of type imports. TypeScript 3.8 added support for type-only imports. Type-only imports allow you to specify that an import can only be used in a type location, allowing certain optimizations within compilers. + <p>This rule aims to standardize the use of type imports style across the codebase.</p> + + + + Major + + + + + + + + + false + false + @typescript-eslint/explicit-function-return-type + TS Best Practices + + true + explicit-function-return-type + Require explicit return types on functions and class methods. Explicit types for function return values makes it clear to any calling code what type is returned. This ensures that the return value is assigned to a variable of the correct type; or in the case where there is no return value, that the calling code doesn't try to use the undefined value when it shouldn't. + <p>This rule aims to ensure that the values returned from functions are of the expected type.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/explicit-member-accessibility + TS Best Practices + + true + explicit-member-accessibility + Require explicit accessibility modifiers on class properties and methods. Leaving off accessibility modifier and making everything public can make your interface hard to use by others. If you make all internal pieces private or protected, your interface will be easier to use. + <p>This rule aims to make code more readable and explicit about who can use which properties.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/explicit-module-boundary-types + TS Best Practices + + true + explicit-module-boundary-types + Require explicit return and argument types on exported functions' and classes' public class methods. Explicit types for function return values and arguments makes it clear to any calling code what is the module boundary's input and output. + <p>This rule aims to ensure that the values returned from a module are of the expected type.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/naming-convention + TS Best Practices + + true + naming-convention + Enforces naming conventions for everything across a codebase. Enforcing naming conventions helps keep the codebase consistent, and reduces overhead when thinking about how to name a variable. Additionally, a well-designed style guide can help communicate intent, such as by enforcing all private properties begin with an _, and all global-level constants are written in UPPER_CASE. There are many different rules that have existed over time, but they have had the problem of not having enough granularity, meaning it was hard to have a well defined style guide, and most of the time you needed 3 or more rules at once to enforce different conventions, hoping they didn't conflict. + <p>This rule allows you to enforce conventions for any identifier, using granular selectors to create a fine-grained style guide.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/no-confusing-non-null-assertion + TS Best Practices + + true + no-confusing-non-null-assertion + Disallow non-null assertion in locations that may be confusing. + <p>Using a non-null assertion (!) next to an assign or equals check (= or == or ===) creates code that is confusing as it looks similar to a not equals check (!= !==).</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/no-explicit-any + TS Best Practices + + true + no-explicit-any + Disallow usage of the any type. Using the any type defeats the purpose of using TypeScript. When any is used, all compiler type checks around that value are ignored. + <p>This rule doesn't allow any types to be defined. It aims to keep TypeScript maximally useful. TypeScript has a compiler flag for --noImplicitAny that will prevent an any type from being implied by the compiler, but doesn't prevent any from being explicitly used.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/no-extra-non-null-assertion + TS Best Practices + + true + no-extra-non-null-assertion + Disallow extra non-null assertion. + <p>Disallow extra non-null assertion.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/no-namespace + TS Best Practices + + true + no-namespace + Disallow the use of custom TypeScript modules and namespaces. Custom TypeScript modules (module foo {}) and namespaces (namespace foo {}) are considered outdated ways to organize TypeScript code. ES2015 module syntax is now preferred (import/export). This rule still allows the use of TypeScript module declarations to describe external APIs (declare module 'foo' {}). + <p>This rule aims to standardize the way modules are declared.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/no-non-null-asserted-nullish-coalescing + TS Best Practices + + true + no-non-null-asserted-nullish-coalescing + Disallows using a non-null assertion in the left operand of the nullish coalescing operator. + <p>The nullish coalescing operator is designed to provide a default value when dealing with null or undefined. Using non-null assertions in the left operand of the nullish coalescing operator is redundant.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/no-non-null-assertion + TS Best Practices + + true + no-non-null-assertion + Disallows non-null assertions using the ! postfix operator. + <p>Using non-null assertions cancels the benefits of the strict null-checking mode.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/no-parameter-properties + TS Best Practices + + true + no-parameter-properties + Disallow the use of parameter properties in class constructors. + <p>This rule disallows the use of parameter properties in constructors, forcing the user to explicitly declare all properties in the class.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/no-unnecessary-boolean-literal-compare + TS Best Practices + + true + no-unnecessary-boolean-literal-compares + Flags unnecessary equality comparisons against boolean literals. Comparing boolean values to boolean literals is unnecessary, those comparisons result in the same booleans. Using the boolean values directly, or via a unary negation (!value), is more concise and clearer. + <p>This rule ensures that you do not include unnecessary comparisons with boolean literals. A comparison is considered unnecessary if it checks a boolean literal against any variable with just the boolean type. A comparison is not considered unnecessary if the type is a union of booleans (string | boolean, someObject | boolean).</p> + + + + Major + + + + + + + + + false + false + @typescript-eslint/prefer-for-of + TS Best Practices + + true + prefer-for-of + Prefer a ‘for-of’ loop over a standard ‘for’ loop if the index is only used to access the array being iterated. + <p>For cases where the index is only used to read from the array being iterated, a for-of loop is easier to read and write.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/prefer-function-type + TS Best Practices + + true + prefer-function-type + Use function types instead of interfaces with call signatures. + <p>This rule suggests using a function type instead of an interface or object type literal with a single call signature.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/prefer-includes + TS Best Practices + + true + prefer-includes + Enforce includes method over indexOf method. + <p>This rule is aimed at suggesting includes method if indexOf method was used to check whether an object contains an arbitrary value or not. If the receiver object of the indexOf method call has includes method and the two methods have the same parameters, this rule does suggestion. There are such types: String, Array, ReadonlyArray, and typed arrays.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/prefer-literal-enum-member + TS Best Practices + + true + prefer-literal-enum-member + Require that all enum members be literal values to prevent unintended enum member name shadow issues. + <p>This rule is meant to prevent unexpected results in code by requiring the use of literal values as enum members to prevent unexpected runtime behavior. Template literals, arrays, objects, constructors, and all other expression types can end up using a variable from its scope or the parent scope, which can result in the same unexpected behavior at runtime.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/prefer-namespace-keyword + TS Best Practices + + true + prefer-namespace-keyword + Require the use of the namespace keyword instead of the module keyword to declare custom TypeScript modules. In an effort to prevent further confusion between custom TypeScript modules and the new ES2015 modules, starting with TypeScript v1.5 the keyword namespace is now the preferred way to declare custom TypeScript modules. + <p>This rule aims to standardize the way modules are declared.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/prefer-nullish-coalescing + TS Best Practices + + true + prefer-nullish-coalescing + Enforce the usage of the nullish coalescing operator instead of logical chaining. + <p>TypeScript 3.7 added support for the nullish coalescing operator. This operator allows you to safely cascade a value when dealing with null or undefined.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/prefer-optional-chain + TS Best Practices + + true + prefer-optional-chain + Prefer using concise optional chain expressions instead of chained logical ands. + <p>This rule aims enforce the usage of the safer operator.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/prefer-readonly + TS Best Practices + + true + prefer-readonly + Requires that private members are marked as readonly if they're never modified outside of the constructor. + <p>Member variables with the privacy private are never permitted to be modified outside of their declaring class. If that class never modifies their value, they may safely be marked as readonly.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/prefer-readonly-parameter-types + TS Best Practices + + true + prefer-readonly-parameter-types + Requires that function parameters are typed as readonly to prevent accidental mutation of inputs. + <p>This rule allows you to enforce that function parameters resolve to readonly types.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/prefer-reduce-type-parameter + TS Best Practices + + true + prefer-reduce-type-parameter + Prefer using type parameter when calling Array#reduce instead of casting. + <p>This rule looks for calls to Array#reduce, and warns if an initial value is being passed and casted, suggesting instead to pass the cast type to Array#reduce as its generic parameter.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/prefer-regexp-exec + TS Best Practices + + true + prefer-regexp-exec + Enforce that RegExp#exec is used instead of String#match if no global flag is provided. + <p>This rule is aimed at enforcing a consistent way to apply regular expressions to strings.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/prefer-return-this-type + TS Best Practices + + true + prefer-return-this-type + Enforce that this is used when only this type is returned. + <p>-</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/prefer-string-starts-ends-with + TS Best Practices + + true + prefer-string-starts-ends-with + Enforce the use of String#startsWith and String#endsWith instead of other equivalent methods of checking substrings. + <p>This rule is aimed at enforcing a consistent way to check whether a string starts or ends with a specific string.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/prefer-ts-expect-error + TS Best Practices + + true + prefer-ts-expect-error + Recommends using @ts-expect-error over @ts-ignore. + <p>This rule looks for usages of @ts-ignore, and flags them to be replaced with @ts-expect-error.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/restrict-template-expressions + TS Best Practices + + true + restrict-template-expressions + Enforce template literal expressions to be of string type. + <p>-</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/strict-boolean-expressions + TS Best Practices + + true + strict-boolean-expressions + Restricts the types allowed in boolean expressions. + <p>Forbids usage of non-boolean types in expressions where a boolean is expected. boolean and never types are always allowed. Additional types which are considered safe in a boolean context can be configured via options.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/switch-exhaustiveness-check + TS Best Practices + + true + switch-exhaustiveness-check + Exhaustiveness checking in switch with union type. + <p>Union type may have a lot of parts. It's easy to forget to consider all cases in switch. This rule reminds which parts are missing. If domain of the problem requires to have only a partial switch, developer may explicitly add a default clause.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/triple-slash-reference + TS Best Practices + + true + triple-slash-reference + Sets preference level for triple slash directives versus ES6-style import declarations. + <p>-</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/unbound-method + TS Best Practices + + true + unbound-method + Enforces unbound methods are called with their expected scope. + <p>Warns when a method is used outside of a method call.</p> + + + + Major + + + + + + + + + + + + + + + + + false + false + @typescript-eslint/init-declarations + TS Variables + + true + init-declarations + Require or disallow initialization in variable declarations. + <p>This rule extends the base eslint/init-declarations rule. It adds support for TypeScript's declare variables.</p> + + + + Major + { "ignoreForLoopInit": true } + + + + + + + + false + false + @typescript-eslint/no-shadow + TS Variables + + true + no-shadow + Disallow variable declarations from shadowing variables declared in the outer scope. + <p>This rule extends the base eslint/no-shadow rule. It adds support for TypeScript's this parameters and global augmentation, and adds options for TypeScript features.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/no-unused-vars + TS Variables + + true + no-unused-vars + Disallow unused variables. + <p>This rule extends the base eslint/no-unused-vars rule. It adds support for TypeScript features, such as types.</p> + + + + Major + { "vars": "all", "args": "after-used" } + + + + + + + + false + false + @typescript-eslint/no-use-before-define + TS Variables + + true + no-use-before-define + Disallow the use of variables before they are defined. + <p>This rule extends the base eslint/no-use-before-define rule. It adds support for type, interface and enum declarations.</p> + + + + Major + { "functions": true,"classes": true,"variables": true,"enums": true,"typedefs": true,"ignoreTypeReferences": true} + + + + + + + + false + false + @typescript-eslint/no-inferrable-types + TS Variables + + true + no-inferrable-types + Disallows explicit type declarations for variables or parameters initialized to a number, string, or boolean. + <p>This rule disallows explicit type declarations on parameters, variables and properties where the type can be easily inferred from its value.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/no-invalid-void-type + TS Variables + + true + no-invalid-void-type + Disallows usage of void type outside of generic or return types. + <p>This rule aims to ensure that the void type is only used in valid places.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/no-meaningless-void-operator + TS Variables + + true + no-meaningless-void-operator + Disallow the void operator except when used to discard a value. + <p>The void operator is a useful tool to convey the programmer's intent to discard a value. For example, it is recommended as one way of suppressing @typescript-eslint/no-floating-promises instead of adding .catch() to a promise.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/no-misused-new + TS Variables + + true + no-misused-new + Enforce valid definition of new and constructor. + <p>Warns on apparent attempts to define constructors for interfaces or new for classes.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/no-this-alias + TS Variables + + true + no-this-alias + Disallow aliasing this. + <p>This rule prohibits assigning variables to this.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/no-type-alias + TS Variables + + true + no-type-alias + Disallow the use of type aliases. + <p>Disallow the use of type aliases.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/no-unnecessary-condition + TS Variables + + true + no-unnecessary-condition + Prevents conditionals where the type is always truthy or always falsy. + <p>Any expression being used as a condition must be able to evaluate as truthy or falsy in order to be considered "necessary". Conversely, any expression that always evaluates to truthy or always evaluates to falsy, as determined by the type of the expression, is considered unnecessary and will be flagged by this rule.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/no-unnecessary-qualifier + TS Variables + + true + no-unnecessary-qualifier + Warns when a namespace qualifier is unnecessary. + <p>This rule aims to let users know when a namespace or enum qualifier is unnecessary, whether used for a type or for a value.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/no-unnecessary-type-arguments + TS Variables + + true + no-unnecessary-type-arguments + Enforces that type arguments will not be used if not required. Warns if an explicitly specified type argument is the default for that type parameter. + <p>Type parameters in TypeScript may specify a default value.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/no-unnecessary-type-assertion + TS Variables + + true + no-unnecessary-type-assertion + Warns if a type assertion does not change the type of an expression. + <p>This rule aims to prevent unnecessary type assertions.</p> + + + + Major + + + + + + + + true + false + @typescript-eslint/no-unnecessary-type-constraint + TS Variables + + true + no-unnecessary-type-constraint + Disallows unnecessary constraints on generic types. + <p>-</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/prefer-enum-initializers + TS Variables + + true + prefer-enum-initializers + Prefer initializing each enums member value. + <p>This rule recommends having each enums member value explicitly initialized.</p> + + + + Major + + + + + + + + false + false + @typescript-eslint/sort-type-union-intersection-members + TS Variables + + true + sort-type-union-intersection-members + Enforces that members of a type union/intersection are sorted alphabetically. + <p>-</p> + + + + Major + + + + + + + + + + + + \ No newline at end of file diff --git a/cl/JAN2Lim/inc/CommentVisitor.h b/cl/JAN2Lim/inc/CommentVisitor.h index a86d1ad..0de8e32 100644 --- a/cl/JAN2Lim/inc/CommentVisitor.h +++ b/cl/JAN2Lim/inc/CommentVisitor.h @@ -29,7 +29,7 @@ namespace columbus { namespace JAN2Lim class CommentVisitor : public lim::asg::VisitorAbstractNodes { public: - CommentVisitor( lim::asg::Factory& f ) : factory( f ), revEdges( f.getReverseEdges() ), pass( 1 ) {} + CommentVisitor( lim::asg::Factory& f ) : revEdges( f.getReverseEdges() ), pass( 1 ) {} virtual void visit( const lim::asg::logical::Package& node, bool ); virtual void visit( const lim::asg::logical::Method& node, bool ); @@ -38,7 +38,6 @@ namespace columbus { namespace JAN2Lim void setPass( int pass ); private: - lim::asg::Factory& factory; const lim::asg::ReverseEdges& revEdges; /** diff --git a/cl/JAN2Lim/src/HalsteadVisitor.cpp b/cl/JAN2Lim/src/HalsteadVisitor.cpp index 6a239fa..0e13e8e 100644 --- a/cl/JAN2Lim/src/HalsteadVisitor.cpp +++ b/cl/JAN2Lim/src/HalsteadVisitor.cpp @@ -429,7 +429,7 @@ namespace columbus { cout << ".class"; } else { - throw columbus::Exception(COLUMBUS_LOCATION, "Unhandled Literal type: " + literal->getNodeKind()); + throw columbus::Exception(COLUMBUS_LOCATION, "Unhandled Literal type" ); } cout << ", "; } diff --git a/cl/JAN2Lim/src/JAN2LimVisitor.cpp b/cl/JAN2Lim/src/JAN2LimVisitor.cpp index c3879f3..2472636 100644 --- a/cl/JAN2Lim/src/JAN2LimVisitor.cpp +++ b/cl/JAN2Lim/src/JAN2LimVisitor.cpp @@ -1959,7 +1959,7 @@ namespace columbus { namespace JAN2Lim } if ( calledMethodId ) { - if ( !usesStack.empty() ) { + if ( !usesStack.empty() && invokes->getMethodType() ) { usesStack.top().insert( getLimType(*invokes->getMethodType()).getId() ); } } diff --git a/cl/JSAN2Lim/src/HalsteadVisitor.cpp b/cl/JSAN2Lim/src/HalsteadVisitor.cpp index 59f3612..b4ca5f9 100644 --- a/cl/JSAN2Lim/src/HalsteadVisitor.cpp +++ b/cl/JSAN2Lim/src/HalsteadVisitor.cpp @@ -446,7 +446,7 @@ namespace columbus { void HalsteadVisitor::visit(const javascript::asg::statement::Function& node, bool callVirtualBase) { VISIT_BEGIN(node, callVirtualBase, "Function"); - if (javascript::asg::Common::getIsFunctionExpression(node) && javascript::asg::Common::getIsMethodDefinition(*node.getParent())) { + if (javascript::asg::Common::getIsFunctionExpression(node) && node.getParent() && javascript::asg::Common::getIsMethodDefinition(*node.getParent())) { return; } enterMethod(node); @@ -458,7 +458,7 @@ namespace columbus { void HalsteadVisitor::visitEnd(const javascript::asg::statement::Function& node, bool callVirtualBase) { VISIT_END_FIRST(node, "Function"); - if (javascript::asg::Common::getIsFunctionExpression(node) && javascript::asg::Common::getIsMethodDefinition(*node.getParent())) { + if (javascript::asg::Common::getIsFunctionExpression(node) && node.getParent() && javascript::asg::Common::getIsMethodDefinition(*node.getParent())) { return; } leaveMethod(node); @@ -483,7 +483,7 @@ namespace columbus { void HalsteadVisitor::visit(const javascript::asg::expression::FunctionExpression& node, bool callVirtualBase) { VISIT_BEGIN(node, callVirtualBase, "FunctionExpression"); - if (javascript::asg::Common::getIsMethodDefinition(*node.getParent())) { + if (node.getParent() && javascript::asg::Common::getIsMethodDefinition(*node.getParent())) { return; } incOperators(getEnumText(opkFunctionDeclaration)); diff --git a/cl/JSAN2Lim/src/JSAN2LimVisitor.cpp b/cl/JSAN2Lim/src/JSAN2LimVisitor.cpp index 91f83fe..2c7ac50 100644 --- a/cl/JSAN2Lim/src/JSAN2LimVisitor.cpp +++ b/cl/JSAN2Lim/src/JSAN2LimVisitor.cpp @@ -524,12 +524,16 @@ namespace JSAN2Lim { MethodInfo& methodInfo = methodStack.top(); //methodInfo.LOC = functionNode.getPosition().getEndLine() - functionNode.getPosition().getLine() + 1; // why not in visit lim::asg::logical::Method& method = dynamic_cast(limFactory.getRef(methodInfo.methodNodeId)); + //set program + if (packageStack.size() != 0) { + if (packageStack.top().NL < methodStack.top().NL) { + packageStack.top().NL = methodStack.top().NL; + } + if (packageStack.top().NLE < methodStack.top().NLE) { + packageStack.top().NLE = methodStack.top().NLE; + } + } - //set program NL - if (packageStack.top().NL < methodStack.top().NL) - packageStack.top().NL = methodStack.top().NL; - if (packageStack.top().NLE < methodStack.top().NLE) - packageStack.top().NLE = methodStack.top().NLE; fillCollectedMethodData(method, functionNode); lastLimMemberNodeId.pop(); lastLimScopeNodeId.pop(); @@ -578,7 +582,7 @@ namespace JSAN2Lim { } else if (callExpressionNode.getCallee() && javascript::asg::Common::getIsMemberExpression(*callExpressionNode.getCallee())) { javascript::asg::expression::MemberExpression& memberExpression = dynamic_cast(*callExpressionNode.getCallee()); - if (javascript::asg::Common::getIsIdentifier(*memberExpression.getProperty())) { + if (memberExpression.getProperty() != nullptr && javascript::asg::Common::getIsIdentifier(*memberExpression.getProperty())) { identifier = dynamic_cast(memberExpression.getProperty()); } } @@ -874,7 +878,8 @@ namespace JSAN2Lim { fileStack.pop(); } if (!packageStack.empty()) { - common::WriteMsg::write(common::WriteMsg::mlDebug, typeid(limFactory.getRef(packageStack.top().packageNodeId)).name()); + auto& ref = limFactory.getRef(packageStack.top().packageNodeId); + common::WriteMsg::write(common::WriteMsg::mlDebug, typeid(ref).name()); packageStack.pop(); } lastLimMemberNodeId.pop(); diff --git a/cl/LIM2Metrics/MET.rul b/cl/LIM2Metrics/MET.rul index 1429338..f840cf3 100644 --- a/cl/LIM2Metrics/MET.rul +++ b/cl/LIM2Metrics/MET.rul @@ -220,200 +220,6 @@ - - - true - true - false - Coupling - - false - Coupling Between Object classes Inverse - - - - 0 - 0 - - - - - true - - false - <b>Class:</b> number of other classes, which directly use the class. Classes which are used by many other classes have a high impact on the behavior of the system, and should be modified very carefully and tested intensively. - <p><strong>Class, Structure, Union, Interface:</strong> number of other classes, which directly use the class. Classes which are used by many other classes have a high impact on the behavior of the system, and should be modified very carefully and tested intensively.</p> - - - - - Class - Interface - Structure - Union - - - - true - - false - <b>Class:</b> number of other classes, which directly use the class. Classes which are used by many other classes have a high impact on the behavior of the system, and should be modified very carefully and tested intensively. - <p><strong>Class, Structure:</strong> number of other classes, which directly use the class. Classes which are used by many other classes have a high impact on the behavior of the system, and should be modified very carefully and tested intensively.</p> - - - - - Class - Interface - Structure - - - - true - - false - <b>Class:</b> number of other classes, which directly use the class. Classes which are used by many other classes have a high impact on the behavior of the system, and should be modified very carefully and tested intensively. - <p><strong>Class:</strong> number of other classes, which directly use the class. Classes which are used by many other classes have a high impact on the behavior of the system, and should be modified very carefully and tested intensively.</p> - - - - - Annotation - Class - Enum - Interface - - - - false - - false - <b>Class:</b> number of other classes, which directly use the class. Classes which are used by many other classes have a high impact on the behavior of the system, and should be modified very carefully and tested intensively. - <p><strong>Class:</strong> number of other classes, which directly use the class. Classes which are used by many other classes have a high impact on the behavior of the system, and should be modified very carefully and tested intensively.</p> - - - - - Class - - - - true - - false - <b>Class:</b> number of other classes, which directly use the class. Classes which are used by many other classes have a high impact on the behavior of the system, and should be modified very carefully and tested intensively. - <p><strong>Class:</strong> number of other classes, which directly use the class. Classes which are used by many other classes have a high impact on the behavior of the system, and should be modified very carefully and tested intensively.</p> - - - - - Class - - - - - - true - true - false - Documentation - - false - Comment Density - - - - 0 - 0 - - - - - true - - false - <b>Method:</b> ratio of the comment lines of the method (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).<br><b>Class:</b> ratio of the comment lines of the class (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).<br><b>Package:</b> ratio of the comment lines of the package (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC). - <p><strong>Method, Function:</strong> ratio of the comment lines of the method (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).</p> <p><strong>Class, Structure, Union:</strong> ratio of the comment lines of the class (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).</p> <p><strong>Namespace:</strong> ratio of the comment lines of the namespace (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).</p> - - - - - Class - Function - Method - Namespace - Structure - Union - - - - true - - false - <b>Method:</b> ratio of the comment lines of the method (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).<br><b>Class:</b> ratio of the comment lines of the class (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).<br><b>Package:</b> ratio of the comment lines of the package (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC). - <p><strong>Method:</strong> ratio of the comment lines of the method (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).</p> <p><strong>Class, Structure:</strong> ratio of the comment lines of the class (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).</p> <p><strong>Namespace:</strong> ratio of the comment lines of the namespace (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).</p> - - - - - Class - Delegate - Method - Namespace - Structure - - - - true - - false - <b>Method:</b> ratio of the comment lines of the method (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).<br><b>Class:</b> ratio of the comment lines of the class (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).<br><b>Package:</b> ratio of the comment lines of the package (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC). - <p><strong>Method:</strong> ratio of the comment lines of the method (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).</p> <p><strong>Class</strong>: ratio of the comment lines of the class (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).</p> <p><strong>Package:</strong> ratio of the comment lines of the package (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).</p> - - - - - Annotation - Class - Enum - Interface - Method - Package - - - - true - - false - <b>Method, function:</b> ratio of the comment lines of the method/function (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).<br><b>Class:</b> ratio of the comment lines of the class (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).<br><b - <p><strong>Method, Function:</strong> ratio of the comment lines of the method/function (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).</p> <p><strong>Class:</strong> ratio of the comment lines of the class (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).</p> - - - - - Class - Function - Method - - - - true - - false - <b>Method/Function:</b> ratio of the comment lines of the method/function (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).<b>Class:</b> ratio of the comment lines of the class (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).<b>Module:</b> ratio of the comment lines of the module (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC). - <p><strong>Method/Function:</strong> ratio of the comment lines of the method/function (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).</p> <p><strong>Class:</strong> ratio of the comment lines of the class (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).</p> <p><strong>Module:</strong> ratio of the comment lines of the module (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC).</p> - - - - - Class - Function - Method - Module - Package - - - true @@ -992,99 +798,84 @@ - + true true - false - Complexity + visual false - Halstead Calculated Program Length + Inheritance metrics - - 0 - 0 - + true false - <b>Method:</b> Halstead Calculated Program Length - <p><strong>Method, Function:</strong></p> <ul> <li><em>n1</em>: number of distinct operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations)</li> <li><em>n2</em>: number of distinct operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations)</li> </ul> <p>The calculated program length is <em>n1 * log<sub>2</sub>(n1) + n2 * log<sub>2</sub>(n2)</em>.</p> + <b>Inheritance metrics:</b> measure the different aspects of the inheritance hierarchy of the system. + <b>Inheritance metrics:</b> measure the different aspects of the inheritance hierarchy of the system. - - Function - Method - + - false + true false - <b>Method:</b> Halstead Calculated Program Length - <b>Method:</b> Halstead Calculated Program Length + <b>Inheritance metrics:</b> measure the different aspects of the inheritance hierarchy of the system. + <b>Inheritance metrics:</b> measure the different aspects of the inheritance hierarchy of the system. - - Method - + - true + false false - <b>Method:</b> Halstead Calculated Program Length - <p><strong>Method:</strong></p> <ul> <li><em>n1</em>: number of distinct operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations)</li> <li><em>n2</em>: number of distinct operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations)</li> </ul> <p>The calculated program length is <em>n1 * log<sub>2</sub>(n1) + n2 * log<sub>2</sub>(n2)</em>.</p> + <b>Inheritance metrics:</b> measure the different aspects of the inheritance hierarchy of the system. + <b>Inheritance metrics:</b> measure the different aspects of the inheritance hierarchy of the system. - - Method - + - false + true false - <b>Method:</b> Halstead Calculated Program Length - <b>Method:</b> Halstead Calculated Program Length + <b>Inheritance metrics:</b> measure the different aspects of the inheritance hierarchy of the system. + <b>Inheritance metrics:</b> measure the different aspects of the inheritance hierarchy of the system. - - Method - + - false + true false - <b>Method:</b> Halstead Calculated Program Length - <b>Method:</b> Halstead Calculated Program Length + <b>Inheritance metrics:</b> measure the different aspects of the inheritance hierarchy of the system. + <b>Inheritance metrics:</b> measure the different aspects of the inheritance hierarchy of the system. - - Method - + - + true true false - Complexity + Cohesion false - Halstead Difficulty + Lack of Cohesion in Methods 5 @@ -1097,78 +888,83 @@ true false - <b>Method:</b> Halstead Difficulty - <p><strong>Method, Function:</strong></p> <ul> <li><em>n1</em>: number of distinct operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations)</li> <li><em>n2</em>: number of distinct operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations)</li> <li><em>N2</em>: total number of operands</li> </ul> <p>The Halstead difficulty is <em>n1/2 * N2/n2</em>.</p> + <b>Class:</b> number of functionalities of the class. One of the basic principles of object-oriented programming is encapsulation, meaning that attributes belonging together and the operations that use them should be organized into one class, and one class shall implement only one functionality, i.e. its attributes and methods should be coherent. This metric measures the lack of cohesion and computes into how many coherent classes the class could be split. It is calculated by taking a non-directed graph, where the nodes are the implemented local methods of the class and there is an edge between the two nodes if and only if a common (local or inherited) attribute or abstract method is used or a method invokes another. The value of the metric is the number of connected components in the graph except the ones that contain only constructors, destructors, getters or setters -- as they are integral parts of the class. + <p><strong>Class, Structure, Union:</strong> number of functionalities of the class. One of the basic principles of object-oriented programming is encapsulation, meaning that attributes belonging together and the operations that use them should be organized into one class, and one class shall implement only one functionality, i.e. its attributes and methods should be coherent. This metric measures the lack of cohesion and computes into how many coherent classes the class could be split. It is calculated by taking a non-directed graph, where the nodes are the implemented local methods of the class and there is an edge between the two nodes if and only if a common (local or inherited) attribute or abstract method is used or a method invokes another. The value of the metric is the number of connected components in the graph not counting those, which contain only constructors, destructors, getters, or setters.</p> - Function - Method + Class + Structure + Union - false + true false - <b>Method:</b> Halstead Difficulty - <b>Method:</b> Halstead Difficulty + <b>Class:</b> number of functionalities of the class. One of the basic principles of object-oriented programming is encapsulation, meaning that attributes belonging together and the operations that use them should be organized into one class, and one class shall implement only one functionality, i.e. its attributes and methods should be coherent. This metric measures the lack of cohesion and computes into how many coherent classes the class could be split. It is calculated by taking a non-directed graph, where the nodes are the implemented local methods of the class and there is an edge between the two nodes if and only if a common (local or inherited) attribute or abstract method is used or a method invokes another. The value of the metric is the number of connected components in the graph except the ones that contain only constructors, destructors, getters or setters -- as they are integral parts of the class. + <p><strong>Class, Structure:</strong> number of functionalities of the class. One of the basic principles of object-oriented programming is encapsulation, meaning that attributes belonging together and the operations that use them should be organized into one class, and one class shall implement only one functionality, i.e. its attributes and methods should be coherent. This metric measures the lack of cohesion and computes into how many coherent classes the class could be split. It is calculated by taking a non-directed graph, where the nodes are the implemented local methods of the class and there is an edge between the two nodes if and only if a common (local or inherited) attribute or abstract method is used or a method invokes another. The value of the metric is the number of connected components in the graph except the ones that contain only constructors, destructors, getters or setters – as they are integral parts of the class.</p> - Method + Class + Structure true false - <b>Method:</b> Halstead Difficulty - <p><strong>Method:</strong></p> <ul> <li><em>n1</em>: number of distinct operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations)</li> <li><em>n2</em>: number of distinct operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations)</li> <li><em>N2</em>: total number of operands</li> </ul> <p>The Halstead difficulty is <em>n1/2 * N2/n2</em>.</p> + <b>Class:</b> number of functionalities of the class. One of the basic principles of object-oriented programming is encapsulation, meaning that attributes belonging together and the operations that use them should be organized into one class, and one class shall implement only one functionality, i.e. its attributes and methods should be coherent. This metric measures the lack of cohesion and computes into how many coherent classes the class could be split. It is calculated by taking a non-directed graph, where the nodes are the implemented local methods of the class and there is an edge between the two nodes if and only if a common (local or inherited) attribute or abstract method is used or a method invokes another. The value of the metric is the number of connected components in the graph not counting those, which contain only constructors, destructors, getters, or setters. + <p><strong>Class:</strong> number of functionalities of the class. One of the basic principles of object-oriented programming is encapsulation, meaning that attributes belonging together and the operations that use them should be organized into one class, and one class shall implement only one functionality, i.e. its attributes and methods should be coherent. This metric measures the lack of cohesion and computes into how many coherent classes the class could be split. It is calculated by taking a non-directed graph, where the nodes are the implemented local methods of the class and there is an edge between the two nodes if and only if a common (local or inherited) attribute or abstract method is used or a method invokes another. The value of the metric is the number of connected components in the graph not counting those, which contain only constructors, destructors, getters, or setters.</p> - Method + Annotation + Class + Enum + Interface false false - <b>Method:</b> Halstead Difficulty - <b>Method:</b> Halstead Difficulty + <b>Class:</b> number of functionalities of the class. One of the basic principles of object-oriented programming is encapsulation, meaning that attributes belonging together and the operations that use them should be organized into one class, and one class shall implement only one functionality, i.e. its attributes and methods should be coherent. This metric measures the lack of cohesion and computes into how many coherent classes the class could be split. It is calculated by taking a non-directed graph, where the nodes are the implemented local methods of the class and there is an edge between the two nodes if and only if a common (local or inherited) attribute or a method invokes another. The value of the metric is the number of connected components in the graph not counting those, which contain only constructors, getters, or setters. + <p><strong>Class:</strong> number of functionalities of the class. One of the basic principles of object-oriented programming is encapsulation, meaning that attributes belonging together and the operations that use them should be organized into one class, and one class shall implement only one functionality, i.e. its attributes and methods should be coherent. This metric measures the lack of cohesion and computes into how many coherent classes the class could be split. It is calculated by taking a non-directed graph, where the nodes are the implemented local methods of the class and there is an edge between the two nodes if and only if a common (local or inherited) attribute or abstract method is used or a method invokes another. The value of the metric is the number of connected components in the graph not counting those, which contain only constructors, getters, or setters.</p> - Method + Class - false + true false - <b>Method:</b> Halstead Difficulty - <b>Method:</b> Halstead Difficulty + <b>Class:</b> number of functionalities of the class. One of the basic principles of object-oriented programming is encapsulation, meaning that attributes belonging together and the operations that use them should be organized into one class, and one class shall implement only one functionality, i.e. its attributes and methods should be coherent. This metric measures the lack of cohesion and computes into how many coherent classes the class could be split. It is calculated by taking a non-directed graph, where the nodes are the implemented local methods of the class and there is an edge between the two nodes if and only if a common (local or inherited) attribute or abstract method is used or a method invokes another. The value of the metric is the number of connected components in the graph not counting those, which contain only constructors. + <p><strong>Class:</strong> number of functionalities of the class. One of the basic principles of object-oriented programming is encapsulation, meaning that attributes belonging together and the operations that use them should be organized into one class, and one class shall implement only one functionality, i.e. its attributes and methods should be coherent. This metric measures the lack of cohesion and computes into how many coherent classes the class could be split. It is calculated by taking a non-directed graph, where the nodes are the implemented local methods of the class and there is an edge between the two nodes if and only if a common (local or inherited) attribute or abstract method is used or a method invokes another. The value of the metric is the number of connected components in the graph not counting those, which contain only constructors.</p> - Method + Class - + true true false - Complexity + Size false - Halstead Effort + Logical Lines of Code @@ -1181,162 +977,106 @@ true false - <b>Method:</b> Halstead Effort - <p><strong>Method, Function:</strong></p> <ul> <li><em>n1</em>: number of distinct operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations)</li> <li><em>n2</em>: number of distinct operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations)</li> <li><em>N1</em>: total number of operators</li> <li><em>N2</em>: total number of operands</li> <li><em>n : n1 + n2</em> (program vocabulary)</li> <li><em>N : N1 + N2</em> (program length)</li> <li><em>V : N * log<sub>2</sub>(n)</em> (volume)</li> <li><em>D : n1/2 * N2/n2</em> (difficulty)</li> </ul> <p>The Halstead effort is <em>D * V</em>.</p> + <b>Method:</b> number of non-empty and non-comment code lines of the method; however, its anonymous and local classes are not included.<br><b>Class:</b> number of non-empty and non-comment code lines of the class, including the non-empty and non-comment lines of its local methods; however, its nested, anonymous, and local classes are not included.<br><b>Package:</b> number of non-empty and non-comment code lines of the package; however, its subpackages are not included.<br><b>File:</b> number of non-empty and non-comment code lines of the file. + <p><strong>Method, Function:</strong> number of non-empty and non-comment code lines of the method; however, its anonymous and local classes are not included.</p> <p><strong>Class, Structure, Union, Interface:</strong> number of non-empty and non-comment code lines of the class, including the non-empty and non-comment lines of its local methods; however, its nested, anonymous, and local classes are not included.</p> <p><strong>Enum:</strong> number of non-empty and non-comment code lines of the enum.</p> <p><strong>Namespace:</strong> number of non-empty and non-comment code lines of the namespace; however, its subnamespaces are not included.</p> <p><strong>File:</strong> number of non-empty and non-comment code lines of the file.</p> + Class + Enum + File Function + Interface Method + Namespace + Structure + Union - false + true false - <b>Method:</b> Halstead Effort - <b>Method:</b> Halstead Effort + <b>Method:</b> number of non-empty and non-comment code lines of the method; however, its anonymous and local classes are not included.<br><b>Class:</b> number of non-empty and non-comment code lines of the class, including the non-empty and non-comment lines of its local methods; however, its nested, anonymous, and local classes are not included.<br><b>Package:</b> number of non-empty and non-comment code lines of the package; however, its subpackages are not included.<br><b>File:</b> number of non-empty and non-comment code lines of the file. + <p><strong>Method:</strong> number of non-empty and non-comment code lines of the method; however, its anonymous classes are not included.</p> <p><strong>Class, Structure:</strong> number of non-empty and non-comment code lines of the class, including the non-empty and non-comment lines of its local methods; however, its nested and anonymous classes are not included.</p> <p><strong>Namespace:</strong> number of non-empty and non-comment code lines of the namespace; however, its subnamespaces are not included.</p> <p><strong>File:</strong> number of non-empty and non-comment code lines of the file.</p> + Class + Delegate + Enum + File + Interface Method + Namespace + Structure true false - <b>Method:</b> Halstead Effort - <p><strong>Method:</strong></p> <ul> <li><em>n1</em>: number of distinct operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations)</li> <li><em>n2</em>: number of distinct operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations)</li> <li><em>N1</em>: total number of operators</li> <li><em>N2</em>: total number of operands</li> <li><em>n : n1 + n2</em> (program vocabulary)</li> <li><em>N : N1 + N2</em> (program length)</li> <li><em>V : N * log<sub>2</sub>(n)</em> (volume)</li> <li><em>D : n1/2 * N2/n2</em> (difficulty)</li> </ul> <p>The Halstead effort is <em>D * V</em>.</p> + <b>Method:</b> number of non-empty and non-comment code lines of the method; however, its anonymous and local classes are not included.<br><b>Class:</b> number of non-empty and non-comment code lines of the class, including the non-empty and non-comment lines of its local methods; however, its nested, anonymous, and local classes are not included.<br><b>Package:</b> number of non-empty and non-comment code lines of the package; however, its subpackages are not included.<br><b>File:</b> number of non-empty and non-comment code lines of the file. + <p><strong>Method:</strong> number of non-empty and non-comment code lines of the method; however, its anonymous and local classes are not included.</p> <p><strong>Class:</strong> number of non-empty and non-comment code lines of the class, including the non-empty and non-comment lines of its local methods; however, its nested, anonymous, and local classes are not included.</p> <p><strong>File:</strong> number of non-empty and non-comment code lines of the file.</p> <p><strong>Package:</strong> number of non-empty and non-comment code lines of the package; however, its subpackages are not included.</p> + Annotation + Class + Enum + File + Interface Method + Package - false - - false - <b>Method:</b> Halstead Effort - <b>Method:</b> Halstead Effort - - - - - Method - - - - false - - false - <b>Method:</b> Halstead Effort - <b>Method:</b> Halstead Effort - - - - - Method - - - - - - true - true - false - Complexity - - false - Halstead Number of Delivered Bugs - - - - 0 - 0 - - - - true false - <b>Method:</b> Halstead Number of Delivered Bugs - <p><strong>Method, Function:</strong></p> <ul> <li><em>n1</em>: number of distinct operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations)</li> <li><em>n2</em>: number of distinct operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations)</li> <li><em>N1</em>: total number of operators</li> <li><em>N2</em>: total number of operands</li> <li><em>n : n1 + n2</em> (program vocabulary)</li> <li><em>N : N1 + N2</em> (program length)</li> <li><em>V : N * log<sub>2</sub>(n)</em> (volume)</li> <li><em>D : n1/2 * N2/n2</em> (difficulty)</li> <li><em>E : D * V</em> (effort)</li> </ul> <p>Number of delivered bugs is <em>E<sup>2/3</sup>/3000</em>.</p> + <b>Method, Function:</b> number of non-empty and non-comment code lines of the method/function; however, its anonymous and local functions are not included.<br><b>Class:</b> number of non-empty and non-comment code lines of the class, including the non-empty and non-comment lines of its local methods; however, its nested, anonymous, and local classes are not included.<br><b>Program:</b> number of non-empty and non-comment code lines of the package.<br><b>File:</b> number of non-empty and non-comment code lines of the file. + <p><strong>Method, Function:</strong> number of non-empty and non-comment code lines of the method/function; however, its anonymous and local functions are not included.</p> <p><strong>Class:</strong> number of non-empty and non-comment code lines of the class, including the non-empty and non-comment lines of its local methods; however, its nested, anonymous, and local classes are not included.</p> <p><strong>File:</strong> number of non-empty and non-comment code lines of the file.</p> + Class + File Function Method - - false - - false - <b>Method:</b> Halstead Number of Delivered Bugs - <b>Method:</b> Halstead Number of Delivered Bugs - - - - - Method - - - - true - - false - <b>Method:</b> Halstead Number of Delivered Bugs - <p><strong>Method:</strong></p> <ul> <li><em>n1</em>: number of distinct operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations)</li> <li><em>n2</em>: number of distinct operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations)</li> <li><em>N1</em>: total number of operators</li> <li><em>N2</em>: total number of operands</li> <li><em>n : n1 + n2</em> (program vocabulary)</li> <li><em>N : N1 + N2</em> (program length)</li> <li><em>V : N * log<sub>2</sub>(n)</em> (volume)</li> <li><em>D : n1/2 * N2/n2</em> (difficulty)</li> <li><em>E : D * V</em> (effort)</li> </ul> <p>Number of delivered bugs is <em>E<sup>2/3</sup>/3000</em>.</p> - - - - - Method - - - - false - - false - <b>Method:</b> Halstead Number of Delivered Bugs - <b>Method:</b> Halstead Number of Delivered Bugs - - - - - Method - - - false + true false - <b>Method:</b> Halstead Number of Delivered Bugs - <b>Method:</b> Halstead Number of Delivered Bugs + <b>Method/Function:</b> number of non-empty and non-comment code lines of the method/function; however, its nested functions are not included.<b>Class:</b> number of non-empty and non-comment code lines of the class, including the non-empty and non-comment lines of its local methods; however, its nested and local classes are not included.<b>Module:</b> number of non-empty and non-comment code lines of the module.<b>Package:</b> number of non-empty and non-comment code lines of the package; however, its subpackages are not included. + <p><strong>Method / Function:</strong> number of non-empty and non-comment code lines of the method/function; however, its nested functions are not included.</p> <p><strong>Class:</strong> number of non-empty and non-comment code lines of the class, including the non-empty and non-comment lines of its local methods; however, its nested and local classes are not included.</p> <p><strong>Module:</strong> number of non-empty and non-comment code lines of the module.</p> <p><strong>Package:</strong> number of non-empty and non-comment code lines of the package; however, its subpackages are not included.</p> <p><strong>File:</strong> number of non-empty and non-comment code lines in the file.</p> + Class + File + Function Method + Module + Package - + true true false - Complexity + Size false - Halstead Program Length + Lines of Code @@ -1349,70 +1089,98 @@ true false - <b>Method:</b> Halstead Program Length - <p><strong>Method, Function:</strong></p> <ul> <li><em>N1</em>: total number of operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations)</li> <li><em>N2</em>: total number of operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations)</li> </ul> <p>Halstead program length is <em>N1 + N2</em>.</p> + <b>Method:</b> number of code lines of the method, including empty and comment lines; however, its anonymous and local classes are not included.<br><b>Class:</b> number of code lines of the class, including empty and comment lines, as well as its local methods; however, its nested, anonymous, and local classes are not included.<br><b>Package:</b> number of code lines of the package, including empty and comment lines; however, its subpackages are not included. + <p><strong>Method, Function:</strong> number of code lines of the method, including empty and comment lines; however, its anonymous and local classes are not included.</p> <p><strong>Class, Structure, Union, Interface:</strong> number of code lines of the class, including empty and comment lines, as well as its local methods; however, its nested, anonymous, and local classes are not included.</p> <p><strong>Enum:</strong> number of code lines of the enum, including empty and comment lines.</p> <p><strong>Namespace:</strong> number of code lines of the namespace, including empty and comment lines; however, its subnamespaces are not included.</p> <p><strong>File:</strong> number of code lines of the file, including empty and comment lines.</p> + Class + Enum + File Function + Interface Method + Namespace + Structure + Union - false + true false - <b>Method:</b> Halstead Program Length - <b>Method:</b> Halstead Program Length + <b>Method:</b> number of code lines of the method, including empty and comment lines; however, its anonymous and local classes are not included.<br><b>Class:</b> number of code lines of the class, including empty and comment lines, as well as its local methods; however, its nested, anonymous, and local classes are not included.<br><b>Package:</b> number of code lines of the package, including empty and comment lines; however, its subpackages are not included. + <p><strong>Method:</strong> number of code lines of the method, including empty and comment lines; however, its anonymous classes are not included.</p> <p><strong>Class, Structure:</strong> number of code lines of the class, including empty and comment lines, as well as its local methods; however, its nested and anonymous classes are not included.</p> <p><strong>Namespace:</strong> number of code lines of the namespace, including empty and comment lines; however, its subnamespaces are not included.</p> + Class + Delegate + Enum + File + Interface Method + Namespace + Structure true false - <b>Method:</b> Halstead Program Length - <p><strong>Method:</strong></p> <ul> <li><em>N1</em>: total number of operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations)</li> <li><em>N2</em>: total number of operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations)</li> </ul> <p>Halstead program length is <em>N1 + N2</em>.</p> + <b>Method:</b> number of code lines of the method, including empty and comment lines; however, its anonymous and local classes are not included.<br><b>Class:</b> number of code lines of the class, including empty and comment lines, as well as its local methods; however, its nested, anonymous, and local classes are not included.<br><b>Package:</b> number of code lines of the package, including empty and comment lines; however, its subpackages are not included. + <p><strong>Method</strong>: number of code lines of the method, including empty and comment lines; however, its anonymous and local classes are not included.</p> <p><strong>Class:</strong> number of code lines of the class, including empty and comment lines, as well as its local methods; however, its nested, anonymous, and local classes are not included.</p> <p><strong>File:</strong> number of code lines of the file.</p> <p><strong>Package:</strong> number of code lines of the package, including empty and comment lines; however, its subpackages are not included.</p> + Annotation + Class + Enum + File + Interface Method + Package - false + true false - <b>Method:</b> Halstead Program Length - <b>Method:</b> Halstead Program Length + <b>Method/function:</b> number of code lines of the method/function, including empty and comment lines; however, its anonymous and local classes are not included.<br><b>Class:</b> number of code lines of the class, including empty and comment lines, as well as its local methods; however, its nested, anonymous, and local classes are not included. + <p><strong>Method, Function:</strong> number of code lines of the method/function, including empty and comment lines; however, its anonymous and local classes are not included.</p> <p><strong>Class:</strong> number of code lines of the class, including empty and comment lines, as well as its local methods; however, its nested, anonymous, and local classes are not included.</p> <p><strong>File:</strong> number of code lines of the file, including empty and comment lines.</p> + Class + File + Function Method - false + true false - <b>Method:</b> Halstead Program Length - <b>Method:</b> Halstead Program Length + <b>Method/Function:</b> number of code lines of the method/function, including empty and comment lines; however, its nested functions are not included.<b>Class:</b> number of code lines of the class, including empty and comment lines, as well as its local methods; however, its nested and local classes are not included.<b>Module:</b> number of code lines of the module, including empty and comment lines.<b>Package:</b> number of code lines of the package, including empty and comment lines; however, its subpackages are not included. + <p><strong>Method / Function:</strong> number of code lines of the method/function, including empty and comment lines; however, its nested functions are not included.</p> <p><strong>Class:</strong> number of code lines of the class, including empty and comment lines, as well as its local methods; however, its nested and local classes are not included.</p> <p><strong>Module:</strong> number of code lines of the module, including empty and comment lines.</p> <p><strong>Package:</strong> number of code lines of the package, including empty and comment lines; however, its subpackages are not included.</p> <p><strong>File:</strong> number of code lines in the file, including empty and comment lines.</p> + Class + File + Function Method + Module + Package - + true true @@ -1420,7 +1188,7 @@ Complexity false - Halstead Program Vocabulary + Maintainability Index (Original version) @@ -1433,8 +1201,7 @@ true false - <b>Method:</b> Program Vocabulary - <p><strong>Method, Function:</strong></p> <ul> <li><em>n1</em>: number of distinct operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations)</li> <li><em>n2</em>: number of distinct operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations)</li> </ul> <p>Halstead program vocabulary is <em>n1 + n2</em>.</p> + <ul> <li><em>HVOL</em>: Halstead Volume</li> <li><em>McCC</em>: McCabe's cyclomatic complexity</li> <li><em>LLOC</em>: logical lines of code</li> </ul> <p>The original Maintainability Index is computed by the following formula:</p> <p><em>MI = 171 - 5.2 * ln(HVOL) - 0.23 * (McCC) - 16.2 * ln(LLOC)</em></p> @@ -1447,8 +1214,6 @@ false false - <b>Method:</b> Program Vocabulary - <b>Method:</b> Program Vocabulary @@ -1460,8 +1225,7 @@ true false - <b>Method:</b> Program Vocabulary - <p><strong>Method:</strong></p> <ul> <li><em>n1</em>: number of distinct operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations)</li> <li><em>n2</em>: number of distinct operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations)</li> </ul> <p>Halstead program vocabulary is <em>n1 + n2</em>.</p> + <ul> <li><em>HVOL</em>: Halstead Volume</li> <li><em>McCC</em>: McCabe’s cyclomatic complexity</li> <li><em>LLOC</em>: logical lines of code</li> </ul> <p>The original Maintainability Index is computed by the following formula:</p> <p><em>MI = 171 - 5.2 * ln(HVOL) - 0.23 * (McCC) - 16.2 * ln(LLOC)</em></p> @@ -1473,8 +1237,6 @@ false false - <b>Method:</b> Program Vocabulary - <b>Method:</b> Program Vocabulary @@ -1486,8 +1248,6 @@ false false - <b>Method:</b> Program Vocabulary - <b>Method:</b> Program Vocabulary @@ -1496,7 +1256,7 @@ - + true true @@ -1504,7 +1264,7 @@ Complexity false - Halstead Time Required to Program + McCabe's Cyclomatic Complexity @@ -1517,26 +1277,28 @@ true false - <b>Method:</b> Halstead Time Required to Program - <p><strong>Method, Function:</strong></p> <ul> <li><em>n1</em>: number of distinct operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations)</li> <li><em>n2</em>: number of distinct operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations)</li> <li><em>N1</em>: total number of operators</li> <li><em>N2</em>: total number of operands</li> <li><em>n : n1 + n2</em> (program vocabulary)</li> <li><em>N : N1 + N2</em> (program length)</li> <li><em>V : N * log<sub>2</sub>(n)</em> (volume)</li> <li><em>D : n1/2 * N2/n2</em> (difficulty)</li> <li><em>E : D * V</em> (effort)</li> </ul> <p>Halstead time required to program is <em>E/18</em> seconds.</p> + <b>Method:</b> complexity of the method expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is initially 1 which increases by 1 for each occurence of the following instructions: if, for, foreach, while, do-while, case label (label that belongs to a switch instruction), catch (handler that belongs to a try block), conditional statement (?:). Moreover, logical and (&&) and logical or (||) expressions also add to the final value because their short-circuit evalutaion can cause branching depending on the first operand. The following language elements do not increase the value: else, try, switch, default label (default label that belongs to a switch instruction), finally. + <p><strong>Method, Function:</strong> complexity of the method expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, for, foreach, range-based for, while, do-while, case label (which belongs to a switch instruction), catch, conditional expression (?:). Moreover, logical &quot;and&quot; (&amp;&amp;) and logical &quot;or&quot; (||) expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, switch, default label (which belongs to a switch instruction), try.</p> <p><strong>File:</strong> complexity of the file expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, for, foreach, range-based for, while, do-while, case label (which belongs to a switch instruction), catch, conditional expression (?:). Moreover, logical &quot;and&quot; (&amp;&amp;) and logical &quot;or&quot; (||) expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, switch, default label (which belongs to a switch instruction), try.</p> + File Function Method - false + true false - <b>Method:</b> Halstead Time Required to Program - <b>Method:</b> Halstead Time Required to Program + <b>Method:</b> complexity of the method expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is initially 1 which increases by 1 for each occurence of the following instructions: if, for, foreach, while, do-while, case label (label that belongs to a switch instruction), catch (handler that belongs to a try block), conditional statement (?:). Moreover, logical and (&&) and logical or (||) expressions also add to the final value because their short-circuit evalutaion can cause branching depending on the first operand. The following language elements do not increase the value: else, try, switch, default label (default label that belongs to a switch instruction), finally. + <p><strong>Method:</strong> complexity of the method expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is initially 1 which increases by 1 for each occurence of the following instructions: if, for, foreach, while, do-while, case label (label that belongs to a switch instruction), catch (handler that belongs to a try block), conditional statement (?:) and conditional access operators (?. and ?[]). Moreover, logical and (&amp;&amp;), logical or (||) and null coalescing (??) expressions also add to the final value because their short-circuit evalutaion can cause branching depending on the first operand. The following language elements do not increase the value: else, try, switch, default label (default label that belongs to a switch instruction), finally.</p> + File Method @@ -1544,52 +1306,56 @@ true false - <b>Method:</b> Halstead Time Required to Program - <p><strong>Method:</strong></p> <ul> <li><em>n1</em>: number of distinct operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations)</li> <li><em>n2</em>: number of distinct operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations)</li> <li><em>N1</em>: total number of operators</li> <li><em>N2</em>: total number of operands</li> <li><em>n : n1 + n2</em> (program vocabulary)</li> <li><em>N : N1 + N2</em> (program length)</li> <li><em>V : N * log<sub>2</sub>(n)</em> (volume)</li> <li><em>D : n1/2 * N2/n2</em> (difficulty)</li> <li><em>E : D * V</em> (effort)</li> </ul> <p>Halstead time required to program is <em>E/18</em> seconds.</p> + <b>Method:</b> complexity of the method expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, for, foreach, while, do-while, case label (which belongs to a switch instruction), catch, conditional statement (?:). Moreover, logical "and" (&&) and logical "or" (||) expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, switch, default label (which belongs to a switch instruction), try, finally. + <p><strong>Method:</strong> complexity of the method expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, for, foreach, while, do-while, case label (which belongs to a switch instruction), catch, conditional statement (?:). Moreover, logical “and” (&amp;&amp;) and logical “or” (||) expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, switch, default label (which belongs to a switch instruction), try, finally.</p> <p><strong>File:</strong> complexity of the file expressed as the number of independent control flow paths in it. It is calculated as the sum of the McCabe’s Cyclomatic Complexity values of the methods can be found in the file.</p> + File Method - false + true false - <b>Method:</b> Halstead Time Required to Program - <b>Method:</b> Halstead Time Required to Program + <p><strong>Method, Function:</strong> complexity of the method expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, else if, for, for...in, for...of, while, do-while, case label (which belongs to a switch instruction), catch clause, conditional expression (?:). Moreover, logical “and” (&amp;&amp;) and logical “or” (||) expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, switch, try, finally.</p> <p><strong>File:</strong> complexity of the file expressed as the number of independent control flow paths in it. It is calculated as the sum of the McCabe’s Cyclomatic Complexity values of the methods can be found in the file.</p> + <p><strong>Method, Function:</strong> complexity of the method expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, else if, for, for…in, for…of, while, do-while, case label (which belongs to a switch instruction), catch clause, conditional expression (?:). Moreover, logical “and” (&amp;&amp;) and logical “or” (||) expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, switch, try, finally.</p> <p><strong>File:</strong> complexity of the file expressed as the number of independent control flow paths in it. It is calculated as the sum of the McCabe’s Cyclomatic Complexity values of the methods can be found in the file.</p> + File Function Method - false + true false - <b>Method:</b> Halstead Time Required to Program - <b>Method:</b> Halstead Time Required to Program + <b>Method/Function:</b> complexity of the method/function expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, for, while, except and conditional expression. Moreover, logical quot;andquot; and logical quot;orquot; expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, try, finally. + <p><strong>Method / Function:</strong> complexity of the method/function expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, for, while, except and conditional expression. Moreover, logical “and” and logical “or” expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, try, finally.</p> <p><strong>File:</strong> complexity of the file expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, for, while, except and conditional expression. Moreover, logical “and” and logical “or” expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, try, finally.</p> + File + Function Method - + true true false - Complexity + Size false - Halstead Volume + Number of Classes @@ -1602,1470 +1368,70 @@ true false - <b>Method:</b> Halstead Volume - <p><strong>Method, Function:</strong></p> <ul> <li><em>n1</em>: number of distinct operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations)</li> <li><em>n2</em>: number of distinct operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations)</li> <li><em>N1</em>: total number of operators</li> <li><em>N2</em>: total number of operands</li> <li><em>n : n1 + n2</em> (program vocabulary)</li> <li><em>N : N1 + N2</em> (program length)</li> </ul> <p>The Halstead volume is <em>N * log<sub>2</sub>(n)</em>.</p> + <b>Package:</b> number of classes in the package; however, the classes of its subpackages are not included. + <p><strong>Namespace:</strong> number of classes in the namespace; however, the classes of its subnamespaces are not included.</p> - Function - Method + Namespace - false - - false - <b>Method:</b> Halstead Volume - <b>Method:</b> Halstead Volume - - - - - Method - - - - true - - false - <b>Method:</b> Halstead Volume - <p><strong>Method:</strong></p> <ul> <li><em>n1</em>: number of distinct operators (semantic meanings of the reserved keywords, semicolons, blocks, and identifiers except in their declarations)</li> <li><em>n2</em>: number of distinct operands (literals - e.g. character, string, and integer literals, - and the identifiers in their declarations)</li> <li><em>N1</em>: total number of operators</li> <li><em>N2</em>: total number of operands</li> <li><em>n : n1 + n2</em> (program vocabulary)</li> <li><em>N : N1 + N2</em> (program length)</li> </ul> <p>The Halstead volume is <em>N * log<sub>2</sub>(n)</em>.</p> - - - - - Method - - - - false - - false - <b>Method:</b> Halstead Volume - <b>Method:</b> Halstead Volume - - - - - Method - - - - false - - false - <b>Method:</b> Halstead Volume - <b>Method:</b> Halstead Volume - - - - - Method - - - - - true - true - visual false - Inheritance metrics + <b>Package:</b> number of classes in the package; however, the classes of its subpackages are not included. + <p><strong>Namespace:</strong> number of classes in the namespace; however, the classes of its subnamespaces are not included.</p> - - - - true - - false - <b>Inheritance metrics:</b> measure the different aspects of the inheritance hierarchy of the system. - <b>Inheritance metrics:</b> measure the different aspects of the inheritance hierarchy of the system. - - - - - - - true - - false - <b>Inheritance metrics:</b> measure the different aspects of the inheritance hierarchy of the system. - <b>Inheritance metrics:</b> measure the different aspects of the inheritance hierarchy of the system. - - - - - - - false - - false - <b>Inheritance metrics:</b> measure the different aspects of the inheritance hierarchy of the system. - <b>Inheritance metrics:</b> measure the different aspects of the inheritance hierarchy of the system. - - - - - - - true - - false - <b>Inheritance metrics:</b> measure the different aspects of the inheritance hierarchy of the system. - <b>Inheritance metrics:</b> measure the different aspects of the inheritance hierarchy of the system. - - - - - - - true - - false - <b>Inheritance metrics:</b> measure the different aspects of the inheritance hierarchy of the system. - <b>Inheritance metrics:</b> measure the different aspects of the inheritance hierarchy of the system. - - - - - - - - - true - true - false - Cohesion - - false - Lack of Cohesion in Methods 5 - - - - 0 - 0 - - - - - true - - false - <b>Class:</b> number of functionalities of the class. One of the basic principles of object-oriented programming is encapsulation, meaning that attributes belonging together and the operations that use them should be organized into one class, and one class shall implement only one functionality, i.e. its attributes and methods should be coherent. This metric measures the lack of cohesion and computes into how many coherent classes the class could be split. It is calculated by taking a non-directed graph, where the nodes are the implemented local methods of the class and there is an edge between the two nodes if and only if a common (local or inherited) attribute or abstract method is used or a method invokes another. The value of the metric is the number of connected components in the graph except the ones that contain only constructors, destructors, getters or setters -- as they are integral parts of the class. - <p><strong>Class, Structure, Union:</strong> number of functionalities of the class. One of the basic principles of object-oriented programming is encapsulation, meaning that attributes belonging together and the operations that use them should be organized into one class, and one class shall implement only one functionality, i.e. its attributes and methods should be coherent. This metric measures the lack of cohesion and computes into how many coherent classes the class could be split. It is calculated by taking a non-directed graph, where the nodes are the implemented local methods of the class and there is an edge between the two nodes if and only if a common (local or inherited) attribute or abstract method is used or a method invokes another. The value of the metric is the number of connected components in the graph not counting those, which contain only constructors, destructors, getters, or setters.</p> - - - - - Class - Structure - Union - - - - true - - false - <b>Class:</b> number of functionalities of the class. One of the basic principles of object-oriented programming is encapsulation, meaning that attributes belonging together and the operations that use them should be organized into one class, and one class shall implement only one functionality, i.e. its attributes and methods should be coherent. This metric measures the lack of cohesion and computes into how many coherent classes the class could be split. It is calculated by taking a non-directed graph, where the nodes are the implemented local methods of the class and there is an edge between the two nodes if and only if a common (local or inherited) attribute or abstract method is used or a method invokes another. The value of the metric is the number of connected components in the graph except the ones that contain only constructors, destructors, getters or setters -- as they are integral parts of the class. - <p><strong>Class, Structure:</strong> number of functionalities of the class. One of the basic principles of object-oriented programming is encapsulation, meaning that attributes belonging together and the operations that use them should be organized into one class, and one class shall implement only one functionality, i.e. its attributes and methods should be coherent. This metric measures the lack of cohesion and computes into how many coherent classes the class could be split. It is calculated by taking a non-directed graph, where the nodes are the implemented local methods of the class and there is an edge between the two nodes if and only if a common (local or inherited) attribute or abstract method is used or a method invokes another. The value of the metric is the number of connected components in the graph except the ones that contain only constructors, destructors, getters or setters – as they are integral parts of the class.</p> - - - - - Class - Structure - - - - true - - false - <b>Class:</b> number of functionalities of the class. One of the basic principles of object-oriented programming is encapsulation, meaning that attributes belonging together and the operations that use them should be organized into one class, and one class shall implement only one functionality, i.e. its attributes and methods should be coherent. This metric measures the lack of cohesion and computes into how many coherent classes the class could be split. It is calculated by taking a non-directed graph, where the nodes are the implemented local methods of the class and there is an edge between the two nodes if and only if a common (local or inherited) attribute or abstract method is used or a method invokes another. The value of the metric is the number of connected components in the graph not counting those, which contain only constructors, destructors, getters, or setters. - <p><strong>Class:</strong> number of functionalities of the class. One of the basic principles of object-oriented programming is encapsulation, meaning that attributes belonging together and the operations that use them should be organized into one class, and one class shall implement only one functionality, i.e. its attributes and methods should be coherent. This metric measures the lack of cohesion and computes into how many coherent classes the class could be split. It is calculated by taking a non-directed graph, where the nodes are the implemented local methods of the class and there is an edge between the two nodes if and only if a common (local or inherited) attribute or abstract method is used or a method invokes another. The value of the metric is the number of connected components in the graph not counting those, which contain only constructors, destructors, getters, or setters.</p> - - - - - Annotation - Class - Enum - Interface - - - - false - - false - <b>Class:</b> number of functionalities of the class. One of the basic principles of object-oriented programming is encapsulation, meaning that attributes belonging together and the operations that use them should be organized into one class, and one class shall implement only one functionality, i.e. its attributes and methods should be coherent. This metric measures the lack of cohesion and computes into how many coherent classes the class could be split. It is calculated by taking a non-directed graph, where the nodes are the implemented local methods of the class and there is an edge between the two nodes if and only if a common (local or inherited) attribute or a method invokes another. The value of the metric is the number of connected components in the graph not counting those, which contain only constructors, getters, or setters. - <p><strong>Class:</strong> number of functionalities of the class. One of the basic principles of object-oriented programming is encapsulation, meaning that attributes belonging together and the operations that use them should be organized into one class, and one class shall implement only one functionality, i.e. its attributes and methods should be coherent. This metric measures the lack of cohesion and computes into how many coherent classes the class could be split. It is calculated by taking a non-directed graph, where the nodes are the implemented local methods of the class and there is an edge between the two nodes if and only if a common (local or inherited) attribute or abstract method is used or a method invokes another. The value of the metric is the number of connected components in the graph not counting those, which contain only constructors, getters, or setters.</p> - - - - - Class - - - - true - - false - <b>Class:</b> number of functionalities of the class. One of the basic principles of object-oriented programming is encapsulation, meaning that attributes belonging together and the operations that use them should be organized into one class, and one class shall implement only one functionality, i.e. its attributes and methods should be coherent. This metric measures the lack of cohesion and computes into how many coherent classes the class could be split. It is calculated by taking a non-directed graph, where the nodes are the implemented local methods of the class and there is an edge between the two nodes if and only if a common (local or inherited) attribute or abstract method is used or a method invokes another. The value of the metric is the number of connected components in the graph not counting those, which contain only constructors. - <p><strong>Class:</strong> number of functionalities of the class. One of the basic principles of object-oriented programming is encapsulation, meaning that attributes belonging together and the operations that use them should be organized into one class, and one class shall implement only one functionality, i.e. its attributes and methods should be coherent. This metric measures the lack of cohesion and computes into how many coherent classes the class could be split. It is calculated by taking a non-directed graph, where the nodes are the implemented local methods of the class and there is an edge between the two nodes if and only if a common (local or inherited) attribute or abstract method is used or a method invokes another. The value of the metric is the number of connected components in the graph not counting those, which contain only constructors.</p> - - - - - Class - - - - - - true - true - false - Size - - false - Logical Lines of Code - - - - 0 - 0 - - - - - true - - false - <b>Method:</b> number of non-empty and non-comment code lines of the method; however, its anonymous and local classes are not included.<br><b>Class:</b> number of non-empty and non-comment code lines of the class, including the non-empty and non-comment lines of its local methods; however, its nested, anonymous, and local classes are not included.<br><b>Package:</b> number of non-empty and non-comment code lines of the package; however, its subpackages are not included.<br><b>File:</b> number of non-empty and non-comment code lines of the file. - <p><strong>Method, Function:</strong> number of non-empty and non-comment code lines of the method; however, its anonymous and local classes are not included.</p> <p><strong>Class, Structure, Union, Interface:</strong> number of non-empty and non-comment code lines of the class, including the non-empty and non-comment lines of its local methods; however, its nested, anonymous, and local classes are not included.</p> <p><strong>Enum:</strong> number of non-empty and non-comment code lines of the enum.</p> <p><strong>Namespace:</strong> number of non-empty and non-comment code lines of the namespace; however, its subnamespaces are not included.</p> <p><strong>File:</strong> number of non-empty and non-comment code lines of the file.</p> - - - - - Class - Enum - File - Function - Interface - Method - Namespace - Structure - Union - - - - true - - false - <b>Method:</b> number of non-empty and non-comment code lines of the method; however, its anonymous and local classes are not included.<br><b>Class:</b> number of non-empty and non-comment code lines of the class, including the non-empty and non-comment lines of its local methods; however, its nested, anonymous, and local classes are not included.<br><b>Package:</b> number of non-empty and non-comment code lines of the package; however, its subpackages are not included.<br><b>File:</b> number of non-empty and non-comment code lines of the file. - <p><strong>Method:</strong> number of non-empty and non-comment code lines of the method; however, its anonymous classes are not included.</p> <p><strong>Class, Structure:</strong> number of non-empty and non-comment code lines of the class, including the non-empty and non-comment lines of its local methods; however, its nested and anonymous classes are not included.</p> <p><strong>Namespace:</strong> number of non-empty and non-comment code lines of the namespace; however, its subnamespaces are not included.</p> <p><strong>File:</strong> number of non-empty and non-comment code lines of the file.</p> - - - - - Class - Delegate - Enum - File - Interface - Method - Namespace - Structure - - - - true - - false - <b>Method:</b> number of non-empty and non-comment code lines of the method; however, its anonymous and local classes are not included.<br><b>Class:</b> number of non-empty and non-comment code lines of the class, including the non-empty and non-comment lines of its local methods; however, its nested, anonymous, and local classes are not included.<br><b>Package:</b> number of non-empty and non-comment code lines of the package; however, its subpackages are not included.<br><b>File:</b> number of non-empty and non-comment code lines of the file. - <p><strong>Method:</strong> number of non-empty and non-comment code lines of the method; however, its anonymous and local classes are not included.</p> <p><strong>Class:</strong> number of non-empty and non-comment code lines of the class, including the non-empty and non-comment lines of its local methods; however, its nested, anonymous, and local classes are not included.</p> <p><strong>File:</strong> number of non-empty and non-comment code lines of the file.</p> <p><strong>Package:</strong> number of non-empty and non-comment code lines of the package; however, its subpackages are not included.</p> - - - - - Annotation - Class - Enum - File - Interface - Method - Package - - - - true - - false - <b>Method, Function:</b> number of non-empty and non-comment code lines of the method/function; however, its anonymous and local functions are not included.<br><b>Class:</b> number of non-empty and non-comment code lines of the class, including the non-empty and non-comment lines of its local methods; however, its nested, anonymous, and local classes are not included.<br><b>Program:</b> number of non-empty and non-comment code lines of the package.<br><b>File:</b> number of non-empty and non-comment code lines of the file. - <p><strong>Method, Function:</strong> number of non-empty and non-comment code lines of the method/function; however, its anonymous and local functions are not included.</p> <p><strong>Class:</strong> number of non-empty and non-comment code lines of the class, including the non-empty and non-comment lines of its local methods; however, its nested, anonymous, and local classes are not included.</p> <p><strong>File:</strong> number of non-empty and non-comment code lines of the file.</p> - - - - - Class - File - Function - Method - - - - true - - false - <b>Method/Function:</b> number of non-empty and non-comment code lines of the method/function; however, its nested functions are not included.<b>Class:</b> number of non-empty and non-comment code lines of the class, including the non-empty and non-comment lines of its local methods; however, its nested and local classes are not included.<b>Module:</b> number of non-empty and non-comment code lines of the module.<b>Package:</b> number of non-empty and non-comment code lines of the package; however, its subpackages are not included. - <p><strong>Method / Function:</strong> number of non-empty and non-comment code lines of the method/function; however, its nested functions are not included.</p> <p><strong>Class:</strong> number of non-empty and non-comment code lines of the class, including the non-empty and non-comment lines of its local methods; however, its nested and local classes are not included.</p> <p><strong>Module:</strong> number of non-empty and non-comment code lines of the module.</p> <p><strong>Package:</strong> number of non-empty and non-comment code lines of the package; however, its subpackages are not included.</p> <p><strong>File:</strong> number of non-empty and non-comment code lines in the file.</p> - - - - - Class - File - Function - Method - Module - Package - - - - - - true - true - false - Size - - false - Lines of Code - - - - 0 - 0 - - - - - true - - false - <b>Method:</b> number of code lines of the method, including empty and comment lines; however, its anonymous and local classes are not included.<br><b>Class:</b> number of code lines of the class, including empty and comment lines, as well as its local methods; however, its nested, anonymous, and local classes are not included.<br><b>Package:</b> number of code lines of the package, including empty and comment lines; however, its subpackages are not included. - <p><strong>Method, Function:</strong> number of code lines of the method, including empty and comment lines; however, its anonymous and local classes are not included.</p> <p><strong>Class, Structure, Union, Interface:</strong> number of code lines of the class, including empty and comment lines, as well as its local methods; however, its nested, anonymous, and local classes are not included.</p> <p><strong>Enum:</strong> number of code lines of the enum, including empty and comment lines.</p> <p><strong>Namespace:</strong> number of code lines of the namespace, including empty and comment lines; however, its subnamespaces are not included.</p> <p><strong>File:</strong> number of code lines of the file, including empty and comment lines.</p> - - - - - Class - Enum - File - Function - Interface - Method - Namespace - Structure - Union - - - - true - - false - <b>Method:</b> number of code lines of the method, including empty and comment lines; however, its anonymous and local classes are not included.<br><b>Class:</b> number of code lines of the class, including empty and comment lines, as well as its local methods; however, its nested, anonymous, and local classes are not included.<br><b>Package:</b> number of code lines of the package, including empty and comment lines; however, its subpackages are not included. - <p><strong>Method:</strong> number of code lines of the method, including empty and comment lines; however, its anonymous classes are not included.</p> <p><strong>Class, Structure:</strong> number of code lines of the class, including empty and comment lines, as well as its local methods; however, its nested and anonymous classes are not included.</p> <p><strong>Namespace:</strong> number of code lines of the namespace, including empty and comment lines; however, its subnamespaces are not included.</p> - - - - - Class - Delegate - Enum - File - Interface - Method - Namespace - Structure - - - - true - - false - <b>Method:</b> number of code lines of the method, including empty and comment lines; however, its anonymous and local classes are not included.<br><b>Class:</b> number of code lines of the class, including empty and comment lines, as well as its local methods; however, its nested, anonymous, and local classes are not included.<br><b>Package:</b> number of code lines of the package, including empty and comment lines; however, its subpackages are not included. - <p><strong>Method</strong>: number of code lines of the method, including empty and comment lines; however, its anonymous and local classes are not included.</p> <p><strong>Class:</strong> number of code lines of the class, including empty and comment lines, as well as its local methods; however, its nested, anonymous, and local classes are not included.</p> <p><strong>File:</strong> number of code lines of the file.</p> <p><strong>Package:</strong> number of code lines of the package, including empty and comment lines; however, its subpackages are not included.</p> - - - - - Annotation - Class - Enum - File - Interface - Method - Package - - - - true - - false - <b>Method/function:</b> number of code lines of the method/function, including empty and comment lines; however, its anonymous and local classes are not included.<br><b>Class:</b> number of code lines of the class, including empty and comment lines, as well as its local methods; however, its nested, anonymous, and local classes are not included. - <p><strong>Method, Function:</strong> number of code lines of the method/function, including empty and comment lines; however, its anonymous and local classes are not included.</p> <p><strong>Class:</strong> number of code lines of the class, including empty and comment lines, as well as its local methods; however, its nested, anonymous, and local classes are not included.</p> <p><strong>File:</strong> number of code lines of the file, including empty and comment lines.</p> - - - - - Class - File - Function - Method - - - - true - - false - <b>Method/Function:</b> number of code lines of the method/function, including empty and comment lines; however, its nested functions are not included.<b>Class:</b> number of code lines of the class, including empty and comment lines, as well as its local methods; however, its nested and local classes are not included.<b>Module:</b> number of code lines of the module, including empty and comment lines.<b>Package:</b> number of code lines of the package, including empty and comment lines; however, its subpackages are not included. - <p><strong>Method / Function:</strong> number of code lines of the method/function, including empty and comment lines; however, its nested functions are not included.</p> <p><strong>Class:</strong> number of code lines of the class, including empty and comment lines, as well as its local methods; however, its nested and local classes are not included.</p> <p><strong>Module:</strong> number of code lines of the module, including empty and comment lines.</p> <p><strong>Package:</strong> number of code lines of the package, including empty and comment lines; however, its subpackages are not included.</p> <p><strong>File:</strong> number of code lines in the file, including empty and comment lines.</p> - - - - - Class - File - Function - Method - Module - Package - - - - - - true - true - false - Complexity - - false - Maintainability Index (Original version) - - - - 0 - 0 - - - - - true - - false - <ul> <li><em>HVOL</em>: Halstead Volume</li> <li><em>McCC</em>: McCabe's cyclomatic complexity</li> <li><em>LLOC</em>: logical lines of code</li> </ul> <p>The original Maintainability Index is computed by the following formula:</p> <p><em>MI = 171 - 5.2 * ln(HVOL) - 0.23 * (McCC) - 16.2 * ln(LLOC)</em></p> - - - - - Function - Method - - - - false - - false - - - - - Method - - - - true - - false - <ul> <li><em>HVOL</em>: Halstead Volume</li> <li><em>McCC</em>: McCabe’s cyclomatic complexity</li> <li><em>LLOC</em>: logical lines of code</li> </ul> <p>The original Maintainability Index is computed by the following formula:</p> <p><em>MI = 171 - 5.2 * ln(HVOL) - 0.23 * (McCC) - 16.2 * ln(LLOC)</em></p> - - - - - Method - - - - false - - false - - - - - Method - - - - false - - false - - - - - Method - - - - - - true - true - false - Complexity - - false - Maintainability Index (Microsoft version) - - - - 0 - 0 - - - - - true - - false - <ul> <li><em>HVOL</em>: Halstead Volume</li> <li><em>McCC</em>: McCabe's cyclomatic complexity</li> <li><em>LLOC</em>: logical lines of code</li> </ul> <p>The Maintainability Index used by Microsoft's Visual Studio is computed by the following formula:</p> <p><em>MIMS = max(0,(171 - 5.2 * ln(HVOL) - 0.23 * (McCC) - 16.2 * ln(LLOC)) * 100 / 171)</em></p> - - - - - Function - Method - - - - false - - false - - - - - Method - - - - true - - false - <ul> <li><em>HVOL</em>: Halstead Volume</li> <li><em>McCC</em>: McCabe’s cyclomatic complexity</li> <li><em>LLOC</em>: logical lines of code</li> </ul> <p>The Maintainability Index used by Microsoft’s Visual Studio is computed by the following formula:</p> <p><em>MIMS = max(0,(171 - 5.2 * ln(HVOL) - 0.23 * (McCC) - 16.2 * ln(LLOC)) * 100 / 171)</em></p> - - - - - Method - - - - false - - false - - - - - Method - - - - false - - false - - - - - Method - - - - - - true - true - false - Complexity - - false - Maintainability Index (SEI version) - - - - 0 - 0 - - - - - true - - false - <ul> <li><em>HVOL</em>: Halstead Volume</li> <li><em>McCC</em>: McCabe's cyclomatic complexity</li> <li><em>LLOC</em>: logical lines of code</li> <li><em>CD</em>: comment density</li> </ul> <p>The Maintainability Index derived by the Software Engineering Institute (SEI) is computed by the following formula:</p> <p><em>MISEI = 171 - 5.2 * log<sub>2</sub>(HVOL) - 0.23 * McCC - 16.2 * log<sub>2</sub>(LLOC) + 50 * sin(sqrt(2.4 * CD))</em></p> - - - - - Function - Method - - - - false - - false - - - - - Method - - - - true - - false - <ul> <li><em>HVOL</em>: Halstead Volume</li> <li><em>McCC</em>: McCabe’s cyclomatic complexity</li> <li><em>LLOC</em>: logical lines of code</li> <li><em>CD</em>: comment density</li> </ul> <p>The Maintainability Index derived by the Software Engineering Institute (SEI) is computed by the following formula:</p> <p><em>MISEI = 171 - 5.2 * log<sub>2</sub>(HVOL) - 0.23 * McCC - 16.2 * log<sub>2</sub>(LLOC) + 50 * sin(sqrt(2.4 * CD))</em></p> - - - - - Method - - - - false - - false - - - - - Method - - - - false - - false - - - - - Method - - - - - - true - true - false - Complexity - - false - Maintainability Index (OpenStaticAnalyzer version) - - - - 0 - 0 - - - - - true - - false - <ul> <li><em>HVOL</em>: Halstead Volume</li> <li><em>McCC</em>: McCabe’s cyclomatic complexity</li> <li><em>LLOC</em>: logical lines of code</li> <li><em>CD</em>: comment density</li> </ul> <p>The Maintainability Index proposed by OpenStaticAnalyzer combines the different scaling approach from Microsoft’s version with the inclusion of comment percentage from the Software Engineering Institute (SEI) version into the following formula:</p> <p><em>MISM = max(0, (171 - 5.2 * log<sub>2</sub>(HVOL) - 0.23 * McCC - 16.2 * log<sub>2</sub>(LLOC) + 50 * sin(sqrt(2.4 * CD))) * 100 / 171)</em></p> - - - - - Function - Method - - - - false - - false - - - - - Method - - - - true - - false - <ul> <li><em>HVOL</em>: Halstead Volume</li> <li><em>McCC</em>: McCabe’s cyclomatic complexity</li> <li><em>LLOC</em>: logical lines of code</li> <li><em>CD</em>: comment density</li> </ul> <p>The Maintainability Index proposed by OpenStaticAnalyzer combines the different scaling approach from Microsoft’s version with the inclusion of comment percentage from the Software Engineering Institute (SEI) version into the following formula:</p> <p><em>MISM = max(0, (171 - 5.2 * log<sub>2</sub>(HVOL) - 0.23 * McCC - 16.2 * log<sub>2</sub>(LLOC) + 50 * sin(sqrt(2.4 * CD))) * 100 / 171)</em></p> - - - - - Method - - - - false - - false - - - - - Method - - - - false - - false - - - - - Method - - - - - - true - true - false - Complexity - - false - McCabe's Cyclomatic Complexity - - - - 0 - 0 - - - - - true - - false - <b>Method:</b> complexity of the method expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is initially 1 which increases by 1 for each occurence of the following instructions: if, for, foreach, while, do-while, case label (label that belongs to a switch instruction), catch (handler that belongs to a try block), conditional statement (?:). Moreover, logical and (&&) and logical or (||) expressions also add to the final value because their short-circuit evalutaion can cause branching depending on the first operand. The following language elements do not increase the value: else, try, switch, default label (default label that belongs to a switch instruction), finally. - <p><strong>Method, Function:</strong> complexity of the method expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, for, foreach, range-based for, while, do-while, case label (which belongs to a switch instruction), catch, conditional expression (?:). Moreover, logical &quot;and&quot; (&amp;&amp;) and logical &quot;or&quot; (||) expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, switch, default label (which belongs to a switch instruction), try.</p> <p><strong>File:</strong> complexity of the file expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, for, foreach, range-based for, while, do-while, case label (which belongs to a switch instruction), catch, conditional expression (?:). Moreover, logical &quot;and&quot; (&amp;&amp;) and logical &quot;or&quot; (||) expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, switch, default label (which belongs to a switch instruction), try.</p> - - - - - File - Function - Method - - - - true - - false - <b>Method:</b> complexity of the method expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is initially 1 which increases by 1 for each occurence of the following instructions: if, for, foreach, while, do-while, case label (label that belongs to a switch instruction), catch (handler that belongs to a try block), conditional statement (?:). Moreover, logical and (&&) and logical or (||) expressions also add to the final value because their short-circuit evalutaion can cause branching depending on the first operand. The following language elements do not increase the value: else, try, switch, default label (default label that belongs to a switch instruction), finally. - <p><strong>Method:</strong> complexity of the method expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is initially 1 which increases by 1 for each occurence of the following instructions: if, for, foreach, while, do-while, case label (label that belongs to a switch instruction), catch (handler that belongs to a try block), conditional statement (?:) and conditional access operators (?. and ?[]). Moreover, logical and (&amp;&amp;), logical or (||) and null coalescing (??) expressions also add to the final value because their short-circuit evalutaion can cause branching depending on the first operand. The following language elements do not increase the value: else, try, switch, default label (default label that belongs to a switch instruction), finally.</p> - - - - - File - Method - - - - true - - false - <b>Method:</b> complexity of the method expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, for, foreach, while, do-while, case label (which belongs to a switch instruction), catch, conditional statement (?:). Moreover, logical "and" (&&) and logical "or" (||) expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, switch, default label (which belongs to a switch instruction), try, finally. - <p><strong>Method:</strong> complexity of the method expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, for, foreach, while, do-while, case label (which belongs to a switch instruction), catch, conditional statement (?:). Moreover, logical “and” (&amp;&amp;) and logical “or” (||) expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, switch, default label (which belongs to a switch instruction), try, finally.</p> <p><strong>File:</strong> complexity of the file expressed as the number of independent control flow paths in it. It is calculated as the sum of the McCabe’s Cyclomatic Complexity values of the methods can be found in the file.</p> - - - - - File - Method - - - - true - - false - <p><strong>Method, Function:</strong> complexity of the method expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, else if, for, for...in, for...of, while, do-while, case label (which belongs to a switch instruction), catch clause, conditional expression (?:). Moreover, logical “and” (&amp;&amp;) and logical “or” (||) expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, switch, try, finally.</p> <p><strong>File:</strong> complexity of the file expressed as the number of independent control flow paths in it. It is calculated as the sum of the McCabe’s Cyclomatic Complexity values of the methods can be found in the file.</p> - <p><strong>Method, Function:</strong> complexity of the method expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, else if, for, for…in, for…of, while, do-while, case label (which belongs to a switch instruction), catch clause, conditional expression (?:). Moreover, logical “and” (&amp;&amp;) and logical “or” (||) expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, switch, try, finally.</p> <p><strong>File:</strong> complexity of the file expressed as the number of independent control flow paths in it. It is calculated as the sum of the McCabe’s Cyclomatic Complexity values of the methods can be found in the file.</p> - - - - - File - Function - Method - - - - true - - false - <b>Method/Function:</b> complexity of the method/function expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, for, while, except and conditional expression. Moreover, logical quot;andquot; and logical quot;orquot; expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, try, finally. - <p><strong>Method / Function:</strong> complexity of the method/function expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, for, while, except and conditional expression. Moreover, logical “and” and logical “or” expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, try, finally.</p> <p><strong>File:</strong> complexity of the file expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, for, while, except and conditional expression. Moreover, logical “and” and logical “or” expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, try, finally.</p> - - - - - File - Function - Method - - - - - - true - true - false - Size - - false - Number of Attributes - - - - 0 - 0 - - - - - true - - false - <b>Class:</b> number of attributes in the class, including the inherited ones; however, the attributes of its nested, anonymous, and local classes are not included.<br><b>Package:</b> number of attributes in the package; however, attributes of its subpackages are not included. - <p><strong>Class, Structure, Union, Interface:</strong> number of attributes in the class, including the inherited ones; however, the attributes of its nested, anonymous, and local classes are not included.</p> <p><strong>Enum:</strong> number of enumerators in the enum.</p> <p><strong>Namespace:</strong> number of attributes in the namespace; however, attributes of its subnamespaces are not included.</p> - - - - - Class - Enum - Interface - Namespace - Structure - Union - - - - true - - false - <b>Class:</b> number of attributes in the class, including the inherited ones; however, the attributes of its nested, anonymous, and local classes are not included.<br><b>Package:</b> number of attributes in the package; however, attributes of its subpackages are not included. - <p><strong>Class, Structure:</strong> number of attributes in the class, including the inherited ones and generated ones backing auto properties; however, the attributes of its nested and anonymous classes are not included.</p> <p><strong>Namespace:</strong> number of attributes in the namespace; however, attributes of its subnamespaces are not included.</p> - - - - - Class - Enum - Interface - Namespace - Structure - - - - true - - false - <b>Class:</b> number of attributes in the class, including the inherited ones; however, the attributes of its nested, anonymous, and local classes are not included.<br><b>Package:</b> number of attributes in the package; however, attributes of its subpackages are not included. - <p><strong>Class:</strong> number of attributes in the class, including the inherited ones; however, the attributes of its nested, anonymous, and local classes are not included.</p> <p><strong>Package:</strong> number of attributes in the package; however, attributes of its subpackages are not included.</p> - - - - - Annotation - Class - Enum - Interface - Package - - - - false - - false - <b>Class:</b> number of properties in the class, including the inherited ones; however, the attributes of its nested, anonymous, and local classes are not included.<br><b>Package:</b> number of attributes in the package; however, attributes of its subpackages are not included. - <p><strong>Class:</strong> number of attributes in the class, including the inherited ones; however, the attributes of its nested, anonymous, and local classes are not included.</p> <p><strong>Enum:</strong> number of enumerators in the enum.</p> <p><strong>Namespace:</strong> number of attributes in the namespace; however, attributes of its subnamespaces are not included.</p> - - - - - Class - File - - - - true - - false - <b>Class:</b> number of attributes in the class, including the inherited ones; however, the attributes of its nested and local classes are not included.<b>Module:</b> number of attributes in the module.<b>Package:</b> number of attributes in the package; however, attributes of its subpackages are not included. - <p><strong>Class:</strong> number of attributes in the class, including the inherited ones; however, the attributes of its nested and local classes are not included.</p> <p><strong>Module:</strong> number of attributes in the module.</p> <p><strong>Package:</strong> number of attributes in the package; however, attributes of its subpackages are not included.</p> - - - - - Class - Module - Package - - - - - - true - true - false - Size - - false - Number of Classes - - - - 0 - 0 - - - - - true - - false - <b>Package:</b> number of classes in the package; however, the classes of its subpackages are not included. - <p><strong>Namespace:</strong> number of classes in the namespace; however, the classes of its subnamespaces are not included.</p> - - - - - Namespace - - - - true - - false - <b>Package:</b> number of classes in the package; however, the classes of its subpackages are not included. - <p><strong>Namespace:</strong> number of classes in the namespace; however, the classes of its subnamespaces are not included.</p> - - - - - Namespace - - - - true - - false - <b>Package:</b> number of classes in the package; however, the classes of its subpackages are not included. - <p><strong>Package:</strong> number of classes in the package; however, the classes of its subpackages are not included.</p> - - - - - Package - - - - false - - false - <b>File:</b> number of classes in the file. - <p><strong>File:</strong> number of classes in the file.</p> - - - - - File - - - - true - - false - <b>Module:</b> number of classes in the module.<b>Package:</b> number of classes in the package; however, the classes of its subpackages are not included. - <p><strong>Module:</strong> number of classes in the module.</p> <p><strong>Package:</strong> number of classes in the package; however, the classes of its subpackages are not included.</p> - - - - - Module - Package - - - - - - true - true - false - Size - - false - Number of Enums - - - - 0 - 0 - - - - - true - - false - <b>Package:</b> number of enums in the package; however, the enums of its subpackages are not included. - <p><strong>Namespace:</strong> number of enums in the namespace; however, the enums of its subnamespaces are not included.</p> - - - - - Namespace - - - - true - - false - <b>Package:</b> number of enums in the package; however, the enums of its subpackages are not included. - <p><strong>Namespace:</strong> number of enums in the namespace; however, the enums of its subnamespaces are not included.</p> - - - - - Namespace - - - - true - - false - <b>Package:</b> number of enums in the package; however, the enums of its subpackages are not included. - <p><strong>Package:</strong> number of enums in the package; however, the enums of its subpackages are not included.</p> - - - - - Package - - - - false - - false - - - - - - - false - - false - - - - - - - - - true - true - false - Size - - false - Number of Getters - - - - 0 - 0 - - - - - true - - false - <b>Class:</b> number of getter methods in the class, including the inherited ones; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted.<br><b>Package:</b> number of getter methods in the package; however, getter methods of its subpackages are not included. - <p><strong>Class, Structure, Union, Interface:</strong> number of getter methods in the class, including the inherited ones; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted.</p> <p><strong>Namespace:</strong> number of getter methods in the namespace; however, getter methods of its subnamespaces are not included.</p> - - - - - Class - Interface - Namespace - Structure - Union - - - - true - - false - <b>Class:</b> number of getter methods in the class, including the inherited ones; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted.<br><b>Package:</b> number of getter methods in the package; however, getter methods of its subpackages are not included. - <p><strong>Class, Structure:</strong> number of getter methods in the class, including the inherited ones; however, the getter methods of its nested and anonymous classes are not included. Methods that override abstract methods are not counted.</p> <p><strong>Namespace:</strong> number of getter methods in the namespace; however, getter methods of its subnamespaces are not included.</p> - - - - - Class - Interface - Namespace - Structure - - - - true - - false - <b>Class:</b> number of getter methods in the class, including the inherited ones; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted.<br><b>Package:</b> number of getter methods in the package; however, getter methods of its subpackages are not included. - <p><strong>Class:</strong> number of getter methods in the class, including the inherited ones; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted.</p> <p><strong>Package</strong>: number of getter methods in the package; however, getter methods of its subpackages are not included.</p> - - - - - Annotation - Class - Enum - Interface - Package - - - - true - - false - <b>Class:</b> number of getter methods in the class, including the inherited ones. - <p><strong>Class:</strong> number of getter methods in the class, including the inherited ones.</p> - - - - - Class - - - - false - - false - - - - - Class - Module - Package - - - - - - true - true - false - Coupling - - false - Number of Incoming Invocations - - - - 0 - 0 - - - - - true - - false - <b>Method:</b> number of other methods and attribute initializations which directly call the method. If the method is invoked several times from the same method or attribute initialization, it is counted only once.<br><b>Class:</b> number of other methods and attribute initializations which directly call the local methods of the class. If a method is invoked several times from the same method or attribute initialization, it is counted only once. - <p><strong>Method, Function:</strong> number of other methods and attribute initializations which directly call the method. If the method is invoked several times from the same method or attribute initialization, it is counted only once.</p> <p><strong>Class, Structure, Union, Interface:</strong> number of other methods and attribute initializations which directly call the local methods of the class. If a method is invoked several times from the same method or attribute initialization, it is counted only once.</p> - - - - - Class - Function - Interface - Method - Structure - Union - - - - true - - false - <b>Method:</b> number of other methods and attribute initializations which directly call the method. If the method is invoked several times from the same method or attribute initialization, it is counted only once.<br><b>Class:</b> number of other methods and attribute initializations which directly call the local methods of the class. If a method is invoked several times from the same method or attribute initialization, it is counted only once. - <p><strong>Method:</strong> number of other methods and attribute initializations which directly call the method. If the method is invoked several times from the same method or attribute initialization, it is counted only once.</p> <p><strong>Class, Structure:</strong> number of other methods and attribute initializations which directly call the local methods of the class. If a method is invoked several times from the same method or attribute initialization, it is counted only once.</p> - - - - - Class - Interface - Method - Structure - - - - true - - false - <b>Method:</b> number of other methods and attribute initializations which directly call the method. If the method is invoked several times from the same method or attribute initialization, it is counted only once.<br><b>Class:</b> number of other methods and attribute initializations which directly call the local methods of the class. If a method is invoked several times from the same method or attribute initialization, it is counted only once. - <p><strong>Method:</strong> number of other methods and attribute initializations which directly call the method. If the method is invoked several times from the same method or attribute initialization, it is counted only once.</p> <p><strong>Class:</strong> number of other methods and attribute initializations which directly call the local methods of the class. If a method is invoked several times from the same method or attribute initialization, it is counted only once.</p> - - - - - Annotation - Class - Enum - Interface - Method - - - - true - - false - <b>Function:</b> number of other functions which directly call the function. If the function is invoked several times from the same function, it is counted only once.<b>Method:</b> number of other methods which directly call the method. If the method is invoked several times from the same method, it is counted only once.<br><b>Class:</b> number of other methods which directly call the local methods of the class. If a method is invoked several times from the same method, it is counted only once. - <p><strong>Method, Function:</strong> number of other methods/functions which directly call the method. If the method/function is invoked several times from the same method/function, it is counted only once.</p> <p><strong>Class:</strong> number of other methods/functions which directly call the local methods of the class. If a method is invoked several times from the same method, it is counted only once.</p> - - - - - Class - Function - Method - - - - true - - false - <b>Method/Function:</b> number of other methods/functions and attribute initializations which directly call the method/function. If the method/function is invoked several times from the same method/function or attribute initialization, it is counted only once.<b>Class:</b> number of other methods and attribute initializations which directly call the local methods of the class. If a method is invoked several times from the same method or attribute initialization, it is counted only once. - <p><strong>Method / Function:</strong> number of other methods/functions and attribute initializations which directly call the method/function. If the method/function is invoked several times from the same method/function or attribute initialization, it is counted only once.</p> <p><strong>Class:</strong> number of other methods and attribute initializations which directly call the local methods of the class. If a method is invoked several times from the same method or attribute initialization, it is counted only once.</p> - - - - - Class - Function - Method - - - - - - true - true - false - Size - - false - Number of Interfaces - - - - 0 - 0 - - - - - true - - false - <b>Package:</b> number of interfaces in the package; however, the interfaces of its subpackages are not included. - <p><strong>Namespace:</strong> number of interfaces in the namespace; however, the interfaces of its subnamespaces are not included.</p> - - - - - Namespace - - - - true - - false - <b>Package:</b> number of interfaces in the package; however, the interfaces of its subpackages are not included. - <p><strong>Namespace:</strong> number of interfaces in the namespace; however, the interfaces of its subnamespaces are not included.</p> - - - - - Namespace - - - - true - - false - <b>Package:</b> number of interfaces in the package; however, the interfaces of its subpackages are not included. - <p><strong>Package:</strong> number of interfaces in the package; however, the interfaces of its subpackages are not included.</p> - - - - - Package - - - - false - - false - - - - - - - false - - false - - - - - - - - - true - true - false - Complexity - - false - Nesting Level - - - - 0 - 0 - - - - - true - - false - <b>Method:</b> complexity of the method expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes. The following instructions are taken into account: if, for, while, do-while, switch, conditional statement (?:). The following instructions do not increase the value by themselves; however, if additional embeddednesses can be found in their blocks, they are considered: else, case and default label (which belong to a switch instruction), try, catch, finally.<br><b>Class:</b> complexity of the class expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes. It is calculated as the maximum nesting level (NL) of its local methods and init blocks. - <p><strong>Method, Function:</strong> complexity of the method expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes. The following instructions are taken into account: if, else-if, else, for, while, do-while, switch, try, catch and block statements that are directly inside another block statement. The following instructions do not increase the value by themselves; however, if additional embeddednesses can be found in their blocks, they are considered: case and default label (which belong to a switch instruction).</p> <p><strong>Class, Structure, Union:</strong> complexity of the class expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes. It is calculated as the maximum nesting level (NL) of its local methods.</p> - - - - - Class - Function - Method - Structure - Union - - - - true - - false - <b>Method:</b> complexity of the method expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes. The following instructions are taken into account: if, for, while, do-while, switch, conditional statement (?:). The following instructions do not increase the value by themselves; however, if additional embeddednesses can be found in their blocks, they are considered: else, case and default label (which belong to a switch instruction), try, catch, finally.<br><b>Class:</b> complexity of the class expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes. It is calculated as the maximum nesting level (NL) of its local methods and init blocks. - <p><strong>Method:</strong> complexity of the method expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes. The following instructions are taken into account: if, else-if, else, for, foreach, while, do-while, switch, try, catch, finally, lock, checked, unchecked, fixed, using statement, conditional statement (?:) and block statements that are directly inside another block statement. The following instructions do not increase the value by themselves; however, if additional embeddednesses can be found in their blocks, they are considered: case and default label.</p> <p><strong>Class, Structure:</strong> complexity of the class expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes. It is calculated as the maximum nesting level (NL) of its local methods.</p> - - - - - Class - Method - Structure + + Namespace true false - <b>Method:</b> complexity of the method expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes. The following instructions are taken into account: if, for, while, do-while, switch, conditional statement (?:). The following instructions do not increase the value by themselves; however, if additional embeddednesses can be found in their blocks, they are considered: else, case and default label (which belong to a switch instruction), try, catch, finally.<br><b>Class:</b> complexity of the class expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes. It is calculated as the maximum nesting level (NL) of its local methods and init blocks. - <p><strong>Method:</strong> complexity of the method expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes. The following instructions are taken into account: if, else-if, else, for, while, do-while, switch, try, catch, finally and block statements that are directly inside another block statement. The following instructions do not increase the value by themselves; however, if additional embeddednesses can be found in their blocks, they are considered: case and default label (which belong to a switch instruction).</p> <p><strong>Class:</strong> complexity of the class expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes. It is calculated as the maximum nesting level (NL) of its local methods and init blocks.</p> + <b>Package:</b> number of classes in the package; however, the classes of its subpackages are not included. + <p><strong>Package:</strong> number of classes in the package; however, the classes of its subpackages are not included.</p> - Annotation - Class - Enum - Interface - Method + Package - true + false false - <b>Method/Function:</b> complexity of the method/function expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes. The following instructions are taken into account: if, else-if, else, for, for-in, for-of, while, do-while, switch, try, catch, finally and block statements that are directly inside another block statement. The following instructions do not increase the value by themselves; however, if additional embeddedness can be found in their blocks, they are considered: case and default label (which belong to a switch instruction).<b>Class:</b> complexity of the class expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes. It is calculated as the maximum nesting level (NL) of its local methods.</p> - <p><strong>Method, Function:</strong> complexity of the method/function expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes. The following instructions are taken into account: if, else-if, else, for, for-in, for-of, while, do-while, switch, try, catch, finally and block statements that are directly inside another block statement. The following instructions do not increase the value by themselves; however, if additional embeddedness can be found in their blocks, they are considered: case and default label (which belong to a switch instruction).</p> <p><strong>Class:</strong> complexity of the class expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes. It is calculated as the maximum nesting level (NL) of its local methods.</p> + <b>File:</b> number of classes in the file. + <p><strong>File:</strong> number of classes in the file.</p> - Class - Function - Method + File true false - <b>Method/Function:</b> complexity of the method/function expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes. The following instructions are taken into account: if, for, while, conditional expression. The following instructions do not increase the value by themselves; however, if additional embeddedness can be found in their blocks, they are considered: else, try, except, finally.<b>Class:</b> complexity of the class expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes. It is calculated as the maximum nesting level (NL) of its local methods. - <p><strong>Method / Function:</strong> complexity of the method/function expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes. The following instructions are taken into account: if, else-if, else, for, while, with, try, except, finally.</p> <p><strong>Class:</strong> complexity of the class expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes. It is calculated as the maximum nesting level (NL) of its local methods.</p> + <b>Module:</b> number of classes in the module.<b>Package:</b> number of classes in the package; however, the classes of its subpackages are not included. + <p><strong>Module:</strong> number of classes in the module.</p> <p><strong>Package:</strong> number of classes in the package; however, the classes of its subpackages are not included.</p> - Class - Function - Method + Module + Package - + true true @@ -3073,7 +1439,7 @@ Size false - Number of Local Attributes + Number of Enums @@ -3086,84 +1452,69 @@ true false - <b>Class:</b> number of local (i.e. not inherited) attributes in the class; however, the attributes of nested, anonymous, and local classes are not included. - <p><strong>Class, Structure, Interface:</strong> number of local (i.e. not inherited) attributes in the class; however, the attributes of nested, anonymous, and local classes are not included.</p> + <b>Package:</b> number of enums in the package; however, the enums of its subpackages are not included. + <p><strong>Namespace:</strong> number of enums in the namespace; however, the enums of its subnamespaces are not included.</p> - Class - Interface - Structure + Namespace true false - <b>Class:</b> number of local (i.e. not inherited) attributes in the class; however, the attributes of nested, anonymous, and local classes are not included. - <p><strong>Class, Structure:</strong> number of local (i.e. not inherited) attributes in the class, including generated ones backing auto properties; however, the attributes of nested and anonymous classes are not included.</p> + <b>Package:</b> number of enums in the package; however, the enums of its subpackages are not included. + <p><strong>Namespace:</strong> number of enums in the namespace; however, the enums of its subnamespaces are not included.</p> - Class - Interface - Structure + Namespace true false - <b>Class:</b> number of local (i.e. not inherited) attributes in the class; however, the attributes of nested, anonymous, and local classes are not included. - <p><strong>Class:</strong> number of local (i.e. not inherited) attributes in the class; however, the attributes of nested, anonymous, and local classes are not included.</p> + <b>Package:</b> number of enums in the package; however, the enums of its subpackages are not included. + <p><strong>Package:</strong> number of enums in the package; however, the enums of its subpackages are not included.</p> - Annotation - Class - Enum - Interface + Package false false - <b>Class:</b> number of local (i.e. not inherited) attributes in the class. - <p><strong>Class:</strong> number of local (i.e. not inherited) attributes in the class.</p> - - Class - + - true + false false - <b>Class:</b> number of local (i.e. not inherited) attributes in the class; however, the attributes of nested and local classes are not included. - <p><strong>Class:</strong> number of local (i.e. not inherited) attributes in the class; however, the attributes of nested and local classes are not included.</p> - - Class - + - + true true false - Complexity + Size false - Nesting Level Else-If + Number of Getters @@ -3176,15 +1527,15 @@ true false - <b>Method:</b> complexity of the method expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes, where in the if-else-if construct only the first if instruction is considered. The following instructions are taken into account: if, for, while, do-while, switch, conditional statement (?:). The following instructions do not increase the value by themselves; however, if additional embeddednesses can be found in their blocks, they are considered: else, else if (i.e. in the if-else-if construct the use of else-if does not increase the value of the metric), case and default label (which belong to a switch instruction), try, catch, finally.<br><b>Class:</b> complexity of the class expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes, where in the if-else-if construct only the first if instruction is considered. It is calculated as the maximum nesting level (NLE) of its local methods and init blocks. - <p><strong>Method, Function:</strong> complexity of the method expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes, where in the if-else-if construct only the first if instruction and in case of multiply catch blocks only the first catch is considered. The following instructions are taken into account: if, else, for, while, do-while, switch, try, catch and block statements that are directly inside another block statement. The following instructions do not increase the value by themselves; however, if additional embeddednesses can be found in their blocks, they are considered: else-if (i.e. in the if-else-if construct the use of else-if does not increase the value of the metric), case and default label (which belong to a switch instruction).</p> <p><strong>Class, Structure, Union:</strong> complexity of the class expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes, where in the if-else-if construct only the first if instruction is considered. It is calculated as the maximum nesting level (NLE) of its local methods.</p> + <b>Class:</b> number of getter methods in the class, including the inherited ones; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted.<br><b>Package:</b> number of getter methods in the package; however, getter methods of its subpackages are not included. + <p><strong>Class, Structure, Union, Interface:</strong> number of getter methods in the class, including the inherited ones; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted.</p> <p><strong>Namespace:</strong> number of getter methods in the namespace; however, getter methods of its subnamespaces are not included.</p> Class - Function - Method + Interface + Namespace Structure Union @@ -3193,14 +1544,15 @@ true false - <b>Method:</b> complexity of the method expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes, where in the if-else-if construct only the first if instruction is considered. The following instructions are taken into account: if, for, while, do-while, switch, conditional statement (?:). The following instructions do not increase the value by themselves; however, if additional embeddednesses can be found in their blocks, they are considered: else, else if (i.e. in the if-else-if construct the use of else-if does not increase the value of the metric), case and default label (which belong to a switch instruction), try, catch, finally.<br><b>Class:</b> complexity of the class expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes, where in the if-else-if construct only the first if instruction is considered. It is calculated as the maximum nesting level (NLE) of its local methods and init blocks. - <p><strong>Method:</strong> complexity of the method expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes, where in the if-else-if construct only the first if instruction is considered. The following instructions are taken into account: if, for, foreach, while, do-while, switch, try, catch, finally, lock, checked, unchecked, fixed, using statement, conditional statement (?:) and block statements that are directly inside another block statement. The following instructions do not increase the value by themselves; however, if additional embeddednesses can be found in their blocks, they are considered: else, else-if (i.e. in the if-else-if construct the use of else-if does not increase the value of the metric), case and default label.</p> <p><strong>Class, Structure:</strong> complexity of the class expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes, where in the if-else-if construct only the first if instruction is considered. It is calculated as the maximum nesting level (NLE) of its local methods.</p> + <b>Class:</b> number of getter methods in the class, including the inherited ones; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted.<br><b>Package:</b> number of getter methods in the package; however, getter methods of its subpackages are not included. + <p><strong>Class, Structure:</strong> number of getter methods in the class, including the inherited ones; however, the getter methods of its nested and anonymous classes are not included. Methods that override abstract methods are not counted.</p> <p><strong>Namespace:</strong> number of getter methods in the namespace; however, getter methods of its subnamespaces are not included.</p> Class - Method + Interface + Namespace Structure @@ -3208,8 +1560,8 @@ true false - <b>Method:</b> complexity of the method expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes, where in the if-else-if construct only the first if instruction is considered. The following instructions are taken into account: if, for, while, do-while, switch, conditional statement (?:). The following instructions do not increase the value by themselves; however, if additional embeddednesses can be found in their blocks, they are considered: else, else if (i.e. in the if-else-if construct the use of else-if does not increase the value of the metric), case and default label (which belong to a switch instruction), try, catch, finally.<br><b>Class:</b> complexity of the class expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes, where in the if-else-if construct only the first if instruction is considered. It is calculated as the maximum nesting level (NLE) of its local methods and init blocks. - <p><strong>Method:</strong> complexity of the method expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes, where in the if-else-if construct only the first if instruction is considered. The following instructions are taken into account: if, else, for, while, do-while, switch, try, catch, finally and block statements that are directly inside another block statement. The following instructions do not increase the value by themselves; however, if additional embeddednesses can be found in their blocks, they are considered: else-if (i.e. in the if-else-if construct the use of else-if does not increase the value of the metric), case and default label (which belong to a switch instruction).</p> <p><strong>Class:</strong> complexity of the class expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes, where in the if-else-if construct only the first if instruction is considered. It is calculated as the maximum nesting level (NLE) of its local methods and init blocks.</p> + <b>Class:</b> number of getter methods in the class, including the inherited ones; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted.<br><b>Package:</b> number of getter methods in the package; however, getter methods of its subpackages are not included. + <p><strong>Class:</strong> number of getter methods in the class, including the inherited ones; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted.</p> <p><strong>Package</strong>: number of getter methods in the package; however, getter methods of its subpackages are not included.</p> @@ -3218,41 +1570,37 @@ Class Enum Interface - Method + Package true false - <b>Method/Function:</b> complexity of the method/function expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes, where in the if-else-if construct only the first if instruction is considered. The following instructions are taken into account: if, for, while, conditional expression. The following instructions do not increase the value by themselves; however, if additional embeddedness can be found in their blocks, they are considered: else, else if (i.e. in the if-else-if construct the use of else-if does not increase the value of the metric), try, except, finally.<b>Class:</b> complexity of the class expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes, where in the if-else-if construct only the first if instruction is considered. It is calculated as the maximum nesting level (NLE) of its local methods. - <p><strong>Method, Function:</strong> complexity of the method/function expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes, where in the if-else-if construct only the first if instruction is considered. The following instructions are taken into account: if, for, while, conditional expression. The following instructions do not increase the value by themselves; however, if additional embeddedness can be found in their blocks, they are considered: else, else if (i.e. in the if-else-if construct the use of else-if does not increase the value of the metric), try, except, finally.</p> <p><strong>Class:</strong> complexity of the class expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes, where in the if-else-if construct only the first if instruction is considered. It is calculated as the maximum nesting level (NLE) of its local methods.</p> + <b>Class:</b> number of getter methods in the class, including the inherited ones. + <p><strong>Class:</strong> number of getter methods in the class, including the inherited ones.</p> Class - Function - Method - true + false false - <b>Method/Function:</b> complexity of the method/function expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes, where in the if-else-if construct only the first if instruction is considered. The following instructions are taken into account: if, for, while, conditional expression. The following instructions do not increase the value by themselves; however, if additional embeddedness can be found in their blocks, they are considered: else, else if (i.e. in the if-else-if construct the use of else-if does not increase the value of the metric), try, except, finally.<b>Class:</b> complexity of the class expressed as the depth of the maximum embeddedness of its conditional and iteration block scopes, where in the if-else-if construct only the first if instruction is considered. It is calculated as the maximum nesting level (NLE) of its local methods. - <p><strong>Method / Function:</strong> complexity of the method/function expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes, where in the if-else-if construct only the first if instruction is considered. The following instructions are taken into account: if, else, for, while, with, try, except, finally. The following instructions do not increase the value by themselves; however, if additional embeddedness can be found in their blocks, they are considered: else-if (i.e. in the if-else-if construct the use of else-if does not increase the value of the metric).</p> <p><strong>Class:</strong> complexity of the class expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes, where in the if-else-if construct only the first if instruction is considered. It is calculated as the maximum nesting level (NLE) of its local methods.</p> Class - Function - Method + Module + Package - + true true @@ -3260,7 +1608,7 @@ Size false - Number of Local Getters + Number of Interfaces @@ -3273,60 +1621,49 @@ true false - <b>Class:</b> number of local (i.e. not inherited) getter methods in the class; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted. - <p><strong>Class, Structure, Interface:</strong> number of local (i.e. not inherited) getter methods in the class; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted.</p> + <b>Package:</b> number of interfaces in the package; however, the interfaces of its subpackages are not included. + <p><strong>Namespace:</strong> number of interfaces in the namespace; however, the interfaces of its subnamespaces are not included.</p> - Class - Interface - Structure + Namespace true false - <b>Class:</b> number of local (i.e. not inherited) getter methods in the class; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted. - <p><strong>Class, Structure:</strong> number of local (i.e. not inherited) getter methods in the class; however, the getter methods of its nested and anonymous classes are not included. Methods that override abstract methods are not counted.</p> + <b>Package:</b> number of interfaces in the package; however, the interfaces of its subpackages are not included. + <p><strong>Namespace:</strong> number of interfaces in the namespace; however, the interfaces of its subnamespaces are not included.</p> - Class - Interface - Structure + Namespace true false - <b>Class:</b> number of local (i.e. not inherited) getter methods in the class; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted. - <p><strong>Class:</strong> number of local (i.e. not inherited) getter methods in the class; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted.</p> + <b>Package:</b> number of interfaces in the package; however, the interfaces of its subpackages are not included. + <p><strong>Package:</strong> number of interfaces in the package; however, the interfaces of its subpackages are not included.</p> - Annotation - Class - Enum - Interface + Package - true + false false - <b>Class:</b> number of local (i.e. not inherited) getter methods in the class. - <p><strong>Class:</strong> number of local (i.e. not inherited) getter methods in the class; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted.</p> - - Class - + false @@ -3335,12 +1672,10 @@ - - Class - + - + true true @@ -3348,7 +1683,7 @@ Size false - Number of Local Methods + Number of Local Getters @@ -3361,8 +1696,8 @@ true false - <b>Class:</b> number of local (i.e. not inherited) methods in the class; however, the methods of nested, anonymous, and local classes are not included. - <p><strong>Class, Structure, Interface:</strong> number of local (i.e. not inherited) methods in the class; however, the methods of nested, anonymous, and local classes are not included.</p> + <b>Class:</b> number of local (i.e. not inherited) getter methods in the class; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted. + <p><strong>Class, Structure, Interface:</strong> number of local (i.e. not inherited) getter methods in the class; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted.</p> @@ -3376,8 +1711,8 @@ true false - <b>Class:</b> number of local (i.e. not inherited) methods in the class; however, the methods of nested, anonymous, and local classes are not included. - <p><strong>Class, Structure:</strong> number of local (i.e. not inherited) methods in the class; however, the methods of nested and anonymous classes are not included.</p> + <b>Class:</b> number of local (i.e. not inherited) getter methods in the class; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted. + <p><strong>Class, Structure:</strong> number of local (i.e. not inherited) getter methods in the class; however, the getter methods of its nested and anonymous classes are not included. Methods that override abstract methods are not counted.</p> @@ -3391,8 +1726,8 @@ true false - <b>Class:</b> number of local (i.e. not inherited) methods in the class; however, the methods of nested, anonymous, and local classes are not included. - <p><strong>Class:</strong> number of local (i.e. not inherited) methods in the class; however, the methods of nested, anonymous, and local classes are not included.</p> + <b>Class:</b> number of local (i.e. not inherited) getter methods in the class; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted. + <p><strong>Class:</strong> number of local (i.e. not inherited) getter methods in the class; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted.</p> @@ -3407,8 +1742,8 @@ true false - <b>Class:</b> number of local (i.e. not inherited) methods in the class. - <p><strong>Class:</strong> number of local (i.e. not inherited) methods in the class.</p> + <b>Class:</b> number of local (i.e. not inherited) getter methods in the class. + <p><strong>Class:</strong> number of local (i.e. not inherited) getter methods in the class; however, the getter methods of its nested, anonymous, and local classes are not included. Methods that override abstract methods are not counted.</p> @@ -3417,11 +1752,9 @@ - true + false false - <b>Class:</b> number of local (i.e. not inherited) methods in the class; however, the methods of nested and local classes are not included. - <p><strong>Class:</strong> number of local (i.e. not inherited) methods in the class; however, the methods of nested and local classes are not included.</p> @@ -3430,7 +1763,7 @@ - + true true @@ -3438,7 +1771,7 @@ Size false - Number of Local Public Attributes + Number of Local Methods @@ -3451,8 +1784,8 @@ true false - <b>Class:</b> number of local (i.e. not inherited) public attributes in the class; however, the attributes of nested, anonymous, and local classes are not included. - <p><strong>Class, Structure, Interface:</strong> number of local (i.e. not inherited) public attributes in the class; however, the attributes of nested, anonymous, and local classes are not included.</p> + <b>Class:</b> number of local (i.e. not inherited) methods in the class; however, the methods of nested, anonymous, and local classes are not included. + <p><strong>Class, Structure, Interface:</strong> number of local (i.e. not inherited) methods in the class; however, the methods of nested, anonymous, and local classes are not included.</p> @@ -3466,8 +1799,8 @@ true false - <b>Class:</b> number of local (i.e. not inherited) public attributes in the class; however, the attributes of nested, anonymous, and local classes are not included. - <p><strong>Class, Structure:</strong> number of local (i.e. not inherited) public attributes in the class, including generated ones backing public auto properties; however, the attributes of nested and anonymous classes are not included.</p> + <b>Class:</b> number of local (i.e. not inherited) methods in the class; however, the methods of nested, anonymous, and local classes are not included. + <p><strong>Class, Structure:</strong> number of local (i.e. not inherited) methods in the class; however, the methods of nested and anonymous classes are not included.</p> @@ -3481,8 +1814,8 @@ true false - <b>Class:</b> number of local (i.e. not inherited) public attributes in the class; however, the attributes of nested, anonymous, and local classes are not included. - <p><strong>Class:</strong> number of local (i.e. not inherited) public attributes in the class; however, the attributes of nested, anonymous, and local classes are not included.</p> + <b>Class:</b> number of local (i.e. not inherited) methods in the class; however, the methods of nested, anonymous, and local classes are not included. + <p><strong>Class:</strong> number of local (i.e. not inherited) methods in the class; however, the methods of nested, anonymous, and local classes are not included.</p> @@ -3494,9 +1827,11 @@ - false + true false + <b>Class:</b> number of local (i.e. not inherited) methods in the class. + <p><strong>Class:</strong> number of local (i.e. not inherited) methods in the class.</p> @@ -3505,9 +1840,11 @@ - false + true false + <b>Class:</b> number of local (i.e. not inherited) methods in the class; however, the methods of nested and local classes are not included. + <p><strong>Class:</strong> number of local (i.e. not inherited) methods in the class; however, the methods of nested and local classes are not included.</p> @@ -4189,105 +2526,14 @@ true false - <b>Class:</b> number of classes, interfaces, enums and annotations from which the class is directly inherited. - <p><strong>Class, Structure:</strong> number of classes and interfaces from which the class is directly inherited.</p> - - - - - Class - Interface - Structure - - - - true - - false - <b>Class:</b> number of classes, interfaces, enums and annotations from which the class is directly inherited. - <p><strong>Class:</strong> number of classes, interfaces, enums and annotations from which the class is directly inherited.</p> - - - - - Annotation - Class - Enum - Interface - - - - false - - false - - - - - Class - - - - true - - false - <b>Class:</b> number of classes from which the class is directly inherited. - <p><strong>Class:</strong> number of classes from which the class is directly inherited.</p> - - - - - Class - - - - - - true - true - false - Size - - false - Number of Statements - - - - 0 - 0 - - - - - true - - false - <b>Method:</b> number of statements in the method; however, the statements of its anonymous and local classes are not included.<br><b>Class:</b> number of statements in the class; however, the statements of its nested, anonymous, and local classes are not included. - <p><strong>Method, Function:</strong> number of statements in the method; however, the statements of its anonymous and local classes are not included.</p> <p><strong>Class, Structure, Union:</strong> number of statements in the class; however, the statements of its nested, anonymous, and local classes are not included.</p> <p><strong>File:</strong> number of statements in the file.</p> - - - - - Class - File - Function - Method - Structure - Union - - - - true - - false - <b>Method:</b> number of statements in the method; however, the statements of its anonymous and local classes are not included.<br><b>Class:</b> number of statements in the class; however, the statements of its nested, anonymous, and local classes are not included. - <p><strong>Method:</strong> number of statements in the method; however, the statements of its anonymous classes are not included.</p> <p><strong>Class, Structure:</strong> number of statements in the class; however, the statements of its nested and anonymous classes are not included.</p> + <b>Class:</b> number of classes, interfaces, enums and annotations from which the class is directly inherited. + <p><strong>Class, Structure:</strong> number of classes and interfaces from which the class is directly inherited.</p> Class - Method + Interface Structure @@ -4295,8 +2541,8 @@ true false - <b>Method:</b> number of statements in the method; however, the statements of its anonymous and local classes are not included.<br><b>Class:</b> number of statements in the class; however, the statements of its nested, anonymous, and local classes are not included. - <p><strong>Method:</strong> number of statements in the method; however, the statements of its anonymous and local classes are not included.</p> <p><strong>Class:</strong> number of statements in the class; however, the statements of its nested, anonymous, and local classes are not included.</p> + <b>Class:</b> number of classes, interfaces, enums and annotations from which the class is directly inherited. + <p><strong>Class:</strong> number of classes, interfaces, enums and annotations from which the class is directly inherited.</p> @@ -4305,42 +2551,34 @@ Class Enum Interface - Method - true + false false - <b>Method, Function:</b> number of statements in the method.<br><b>Class:</b> number of statements in the class. <b>File:</b> number of statements in the file. - <p><strong>Method, Function:</strong> number of statements in the method.</p> <p><strong>Class:</strong> number of statements in the class.</p> <p><strong>File:</strong> number of statements in the file.</p> Class - Function - Method true false - <b>Method/Function:</b> number of statements in the method/function; however, the statements of its nested functions are not included.<b>Class:</b> number of statements in the class; however, the statements of its nested and local classes are not included. - <p><strong>Method / Function:</strong> number of statements in the method/function; however, the statements of its nested functions are not included.</p> <p><strong>Class:</strong> number of statements in the class; however, the statements of its nested and local classes are not included.</p> <p><strong>File:</strong> number of statements in the file.</p> + <b>Class:</b> number of classes from which the class is directly inherited. + <p><strong>Class:</strong> number of classes from which the class is directly inherited.</p> Class - File - Function - Method - + true true @@ -4348,7 +2586,7 @@ Size false - Number of Public Attributes + Number of Statements @@ -4361,15 +2599,16 @@ true false - <b>Class:</b> number of public attributes in the class, including the inherited ones; however, the public attributes of its nested, anonymous, and local classes are not included.<br><b>Package:</b> number of public attributes in the package; however, the public attributes of its subpackages are not included. - <p><strong>Class, Structure, Union, Interface:</strong> number of public attributes in the class, including the inherited ones; however, the public attributes of its nested, anonymous, and local classes are not included.</p> <p><strong>Namespace:</strong> number of public attributes in the namespace; however, the public attributes of its subnamespaces are not included.</p> + <b>Method:</b> number of statements in the method; however, the statements of its anonymous and local classes are not included.<br><b>Class:</b> number of statements in the class; however, the statements of its nested, anonymous, and local classes are not included. + <p><strong>Method, Function:</strong> number of statements in the method; however, the statements of its anonymous and local classes are not included.</p> <p><strong>Class, Structure, Union:</strong> number of statements in the class; however, the statements of its nested, anonymous, and local classes are not included.</p> <p><strong>File:</strong> number of statements in the file.</p> Class - Interface - Namespace + File + Function + Method Structure Union @@ -4378,15 +2617,14 @@ true false - <b>Class:</b> number of public attributes in the class, including the inherited ones; however, the public attributes of its nested, anonymous, and local classes are not included.<br><b>Package:</b> number of public attributes in the package; however, the public attributes of its subpackages are not included. - <p><strong>Class, Structure:</strong> number of public attributes in the class, including the inherited ones and generated ones backing public auto properties; however, the public attributes of its nested and anonymous classes are not included.</p> <p><strong>Namespace:</strong> number of public attributes in the namespace; however, the public attributes of its subnamespaces are not included.</p> + <b>Method:</b> number of statements in the method; however, the statements of its anonymous and local classes are not included.<br><b>Class:</b> number of statements in the class; however, the statements of its nested, anonymous, and local classes are not included. + <p><strong>Method:</strong> number of statements in the method; however, the statements of its anonymous classes are not included.</p> <p><strong>Class, Structure:</strong> number of statements in the class; however, the statements of its nested and anonymous classes are not included.</p> Class - Interface - Namespace + Method Structure @@ -4394,8 +2632,8 @@ true false - <b>Class:</b> number of public attributes in the class, including the inherited ones; however, the public attributes of its nested, anonymous, and local classes are not included.<br><b>Package:</b> number of public attributes in the package; however, the public attributes of its subpackages are not included. - <p><strong>Class:</strong> number of public attributes in the class, including the inherited ones; however, the public attributes of its nested, anonymous, and local classes are not included.</p> <p><strong>Package:</strong> number of public attributes in the package; however, the public attributes of its subpackages are not included.</p> + <b>Method:</b> number of statements in the method; however, the statements of its anonymous and local classes are not included.<br><b>Class:</b> number of statements in the class; however, the statements of its nested, anonymous, and local classes are not included. + <p><strong>Method:</strong> number of statements in the method; however, the statements of its anonymous and local classes are not included.</p> <p><strong>Class:</strong> number of statements in the class; however, the statements of its nested, anonymous, and local classes are not included.</p> @@ -4404,31 +2642,38 @@ Class Enum Interface - Package + Method - false + true false + <b>Method, Function:</b> number of statements in the method.<br><b>Class:</b> number of statements in the class. <b>File:</b> number of statements in the file. + <p><strong>Method, Function:</strong> number of statements in the method.</p> <p><strong>Class:</strong> number of statements in the class.</p> <p><strong>File:</strong> number of statements in the file.</p> Class + Function + Method - false + true false + <b>Method/Function:</b> number of statements in the method/function; however, the statements of its nested functions are not included.<b>Class:</b> number of statements in the class; however, the statements of its nested and local classes are not included. + <p><strong>Method / Function:</strong> number of statements in the method/function; however, the statements of its nested functions are not included.</p> <p><strong>Class:</strong> number of statements in the class; however, the statements of its nested and local classes are not included.</p> <p><strong>File:</strong> number of statements in the file.</p> Class - Module - Package + File + Function + Method @@ -5366,114 +3611,6 @@ - - - true - true - false - Documentation - - false - Total Comment Density - - - - 0 - 0 - - - - - true - - false - <b>Method:</b> ratio of the total comment lines of the method (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).<br><b>Class:</b> ratio of the total comment lines of the class (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).<br><b>Package:</b> ratio of the total comment lines of the package (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).<br><b>Component:</b> ratio of the total comment lines of the component (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). - <p><strong>Method, Function:</strong> ratio of the total comment lines of the method (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).</p> <p><strong>Class, Structure, Union:</strong> ratio of the total comment lines of the class (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).</p> <p><strong>Namespace:</strong> ratio of the total comment lines of the namespace (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).</p> <p><strong>Component:</strong> ratio of the total comment lines of the component (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).</p> - - - - - Class - Component - Function - Method - Namespace - Structure - Union - - - - true - - false - <b>Method:</b> ratio of the total comment lines of the method (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).<br><b>Class:</b> ratio of the total comment lines of the class (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).<br><b>Package:</b> ratio of the total comment lines of the package (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).<br><b>Component:</b> ratio of the total comment lines of the component (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). - <p><strong>Method:</strong> ratio of the total comment lines of the method (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).</p> <p><strong>Class, Structure:</strong> ratio of the total comment lines of the class (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).</p> <p><strong>Namespace:</strong> ratio of the total comment lines of the namespace (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).</p> <p><strong>Component:</strong> ratio of the total comment lines of the component (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).</p> - - - - - Class - Component - Delegate - Method - Namespace - Structure - - - - true - - false - <b>Method:</b> ratio of the total comment lines of the method (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).<br><b>Class:</b> ratio of the total comment lines of the class (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).<br><b>Package:</b> ratio of the total comment lines of the package (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).<br><b>Component:</b> ratio of the total comment lines of the component (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). - <p><strong>Method:</strong> ratio of the total comment lines of the method (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).</p> <p><strong>Class:</strong> ratio of the total comment lines of the class (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).</p> <p><strong>Package:</strong> ratio of the total comment lines of the package (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).</p> <p><strong>Component:</strong> ratio of the total comment lines of the component (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).</p> - - - - - Annotation - Class - Component - Enum - Interface - Method - Package - - - - true - - false - <b>Method/Function:</b> ratio of the total comment lines of the method/function (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).<b>Class:</b> ratio of the total comment lines of the class (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).<b>Component:</b> ratio of the total comment lines of the component (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). - <p><strong>Method/Function:</strong> ratio of the total comment lines of the method/function (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).</p> <p><strong>Class:</strong> ratio of the total comment lines of the class (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).</p> <p><strong>Component:</strong> ratio of the total comment lines of the component (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).</p> - - - - - Class - Component - Function - Method - - - - true - - false - <b>Method/Function:</b> ratio of the total comment lines of the method/function (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).<b>Class:</b> ratio of the total comment lines of the class (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).<b>Module:</b> ratio of the total comment lines of the module (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).<b>Package:</b> ratio of the total comment lines of the package (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).<b>Component:</b> ratio of the total comment lines of the component (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). - <p><strong>Method/Function:</strong> ratio of the total comment lines of the method/function (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).</p> <p><strong>Class:</strong> ratio of the total comment lines of the class (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).</p> <p><strong>Module:</strong> ratio of the total comment lines of the module (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).</p> <p><strong>Package:</strong> ratio of the total comment lines of the package (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).</p> <p><strong>Component:</strong> ratio of the total comment lines of the component (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC).</p> - - - - - Class - Component - Function - Method - Module - Package - - - true @@ -5749,114 +3886,7 @@ Delegate Enum Interface - Method - Namespace - Structure - - - - true - - false - <b>Method:</b> number of code lines of the method, including empty and comment lines, as well as its anonymous and local classes.<br><b>Class:</b> number of code lines of the class, including empty and comment lines, as well as its local methods, anonymous, local, and nested classes.<br><b>Package:</b> number of code lines of the package, including empty and comment lines, as well as its subpackages.<br><b>Component:</b> number of code lines of the component, including empty and comment lines, as well as its subcomponents. - <p><strong>Method</strong>: number of code lines of the method, including empty and comment lines, as well as its anonymous and local classes.</p> <p><strong>Class:</strong> number of code lines of the class, including empty and comment lines, as well as its local methods, anonymous, local, and nested classes.</p> <p><strong>Package:</strong> number of code lines of the package, including empty and comment lines, as well as its subpackages.</p> <p><strong>Component:</strong> number of code lines of the component, including empty and comment lines, as well as its subcomponents.</p> - - - - - Annotation - Class - Component - Enum - Interface - Method - Package - - - - true - - false - <b>Method/Function:</b> number of code lines of the method/function, including empty and comment lines, as well as its nested functions.<b>Class:</b> number of code lines of the class, including empty and comment lines, as well as its nested and local classes.<b>Component:</b> number of code lines of the component, including empty and comment lines, as well as its subcomponents. - <p><strong>Method, Function:</strong> number of code lines of the method/function, including empty and comment lines, as well as its nested functions.</p> <p><strong>Class:</strong> number of code lines of the class, including empty and comment lines, as well as its nested and local classes.</p> <p><strong>Component:</strong> number of code lines of the component, including empty and comment lines, as well as its subcomponents.</p> - - - - - Class - Component - Function - Method - - - - true - - false - <b>Method/Function:</b> number of code lines of the method/function, including empty and comment lines, as well as its nested functions.<b>Class:</b> number of code lines of the class, including empty and comment lines, as well as its nested and local classes.<b>Module:</b> number of code lines of the module, including empty and comment lines.<b>Package:</b> number of code lines of the package, including empty and comment lines, as well as its subpackages.<b>Component:</b> number of code lines of the component, including empty and comment lines, as well as its subcomponents. - <p><strong>Method / Function:</strong> number of code lines of the method/function, including empty and comment lines, as well as its nested functions.</p> <p><strong>Class:</strong> number of code lines of the class, including empty and comment lines, as well as its nested and local classes.</p> <p><strong>Module:</strong> number of code lines of the module, including empty and comment lines.</p> <p><strong>Package:</strong> number of code lines of the package, including empty and comment lines, as well as its subpackages.</p> <p><strong>Component:</strong> number of code lines of the component, including empty and comment lines, as well as its subcomponents.</p> - - - - - Class - Component - Function - Method - Module - Package - - - - - - true - true - false - Size - - false - Total Number of Attributes - - - - 0 - 0 - - - - - true - - false - <b>Class:</b> number of attributes in the class, including the inherited ones, as well as the inherited and local attributes of its nested, anonymous and local classes.<br><b>Package:</b> number of attributes in the package, including the attributes of its subpackages.<br><b>Component:</b> number of attributes in the component, including the attributes of its subcomponents. - <p><strong>Class, Structure, Union, Interface:</strong> number of attributes in the class, including the inherited ones, as well as the inherited and local attributes of its nested, anonymous and local classes.</p> <p><strong>Namespace:</strong> number of attributes in the namespace, including the attributes of its subnamespaces.</p> <p><strong>Component:</strong> number of attributes in the component, including the attributes of its subcomponents.</p> - - - - - Class - Component - Enum - Interface - Namespace - Structure - Union - - - - true - - false - <b>Class:</b> number of attributes in the class, including the inherited ones, as well as the inherited and local attributes of its nested, anonymous and local classes.<br><b>Package:</b> number of attributes in the package, including the attributes of its subpackages.<br><b>Component:</b> number of attributes in the component, including the attributes of its subcomponents. - <p><strong>Class, Structure:</strong> number of attributes in the class, including the inherited ones and generated ones backing auto properties, as well as the inherited and local attributes of its nested and anonymous classes.</p> <p><strong>Namespace:</strong> number of attributes in the namespace, including the attributes of its subnamespaces.</p> <p><strong>Component:</strong> number of attributes in the component, including the attributes of its subcomponents.</p> - - - - - Class - Component - Interface + Method Namespace Structure @@ -5865,8 +3895,8 @@ true false - <b>Class:</b> number of attributes in the class, including the inherited ones, as well as the inherited and local attributes of its nested, anonymous and local classes.<br><b>Package:</b> number of attributes in the package, including the attributes of its subpackages.<br><b>Component:</b> number of attributes in the component, including the attributes of its subcomponents. - <p><strong>Class:</strong> number of attributes in the class, including the inherited ones, as well as the inherited and local attributes of its nested, anonymous and local classes.</p> <p><strong>Package:</strong> number of attributes in the package, including the attributes of its subpackages.</p> <p><strong>Component:</strong> number of attributes in the component, including the attributes of its subcomponents.</p> + <b>Method:</b> number of code lines of the method, including empty and comment lines, as well as its anonymous and local classes.<br><b>Class:</b> number of code lines of the class, including empty and comment lines, as well as its local methods, anonymous, local, and nested classes.<br><b>Package:</b> number of code lines of the package, including empty and comment lines, as well as its subpackages.<br><b>Component:</b> number of code lines of the component, including empty and comment lines, as well as its subcomponents. + <p><strong>Method</strong>: number of code lines of the method, including empty and comment lines, as well as its anonymous and local classes.</p> <p><strong>Class:</strong> number of code lines of the class, including empty and comment lines, as well as its local methods, anonymous, local, and nested classes.</p> <p><strong>Package:</strong> number of code lines of the package, including empty and comment lines, as well as its subpackages.</p> <p><strong>Component:</strong> number of code lines of the component, including empty and comment lines, as well as its subcomponents.</p> @@ -5876,35 +3906,40 @@ Component Enum Interface + Method Package - false + true false - <b>Class:</b> number of attributes in the class, including the inherited ones, as well as the inherited and local attributes of its nested and local classes.<b>Component:</b> number of attributes in the component, including the attributes of its subcomponents. - <p><strong>Class:</strong> number of attributes in the class, including the inherited ones, as well as the inherited and local attributes of its nested and local classes.</p> <p><strong>Component:</strong> number of attributes in the component, including the attributes of its subcomponents.</p> + <b>Method/Function:</b> number of code lines of the method/function, including empty and comment lines, as well as its nested functions.<b>Class:</b> number of code lines of the class, including empty and comment lines, as well as its nested and local classes.<b>Component:</b> number of code lines of the component, including empty and comment lines, as well as its subcomponents. + <p><strong>Method, Function:</strong> number of code lines of the method/function, including empty and comment lines, as well as its nested functions.</p> <p><strong>Class:</strong> number of code lines of the class, including empty and comment lines, as well as its nested and local classes.</p> <p><strong>Component:</strong> number of code lines of the component, including empty and comment lines, as well as its subcomponents.</p> Class Component + Function + Method true false - <b>Class:</b> number of attributes in the class, including the inherited ones, as well as the inherited and local attributes of its nested and local classes.<b>Module:</b> number of attributes in the module.<b>Package:</b> number of attributes in the package, including the attributes of its subpackages.<b>Component:</b> number of attributes in the component, including the attributes of its subcomponents. - <p><strong>Class:</strong> number of attributes in the class, including the inherited ones, as well as the inherited and local attributes of its nested and local classes.</p> <p><strong>Module:</strong> number of attributes in the module.</p> <p><strong>Package:</strong> number of attributes in the package, including the attributes of its subpackages.</p> <p><strong>Component:</strong> number of attributes in the component, including the attributes of its subcomponents.</p> + <b>Method/Function:</b> number of code lines of the method/function, including empty and comment lines, as well as its nested functions.<b>Class:</b> number of code lines of the class, including empty and comment lines, as well as its nested and local classes.<b>Module:</b> number of code lines of the module, including empty and comment lines.<b>Package:</b> number of code lines of the package, including empty and comment lines, as well as its subpackages.<b>Component:</b> number of code lines of the component, including empty and comment lines, as well as its subcomponents. + <p><strong>Method / Function:</strong> number of code lines of the method/function, including empty and comment lines, as well as its nested functions.</p> <p><strong>Class:</strong> number of code lines of the class, including empty and comment lines, as well as its nested and local classes.</p> <p><strong>Module:</strong> number of code lines of the module, including empty and comment lines.</p> <p><strong>Package:</strong> number of code lines of the package, including empty and comment lines, as well as its subpackages.</p> <p><strong>Component:</strong> number of code lines of the component, including empty and comment lines, as well as its subcomponents.</p> Class Component + Function + Method Module Package @@ -6427,97 +4462,6 @@ - - - true - true - false - Size - - false - Total Number of Local Attributes - - - - 0 - 0 - - - - - true - - false - <b>Class:</b> number of local (i.e. not inherited) attributes in the class, including the attributes of its nested, anonymous, and local classes. - <p><strong>Class, Structure, Interface:</strong> number of local (i.e. not inherited) attributes in the class, including the attributes of its nested, anonymous, and local classes.</p> - - - - - Class - Interface - Structure - - - - true - - false - <b>Class:</b> number of local (i.e. not inherited) attributes in the class, including the attributes of its nested, anonymous, and local classes. - <p><strong>Class, Structure:</strong> number of local (i.e. not inherited) attributes in the class, including the generated ones backing auto properties and also attributes of its nested and anonymous classes.</p> - - - - - Class - Component - Interface - Structure - - - - true - - false - <b>Class:</b> number of local (i.e. not inherited) attributes in the class, including the attributes of its nested, anonymous, and local classes. - <p><strong>Class:</strong> number of local (i.e. not inherited) attributes in the class, including the attributes of its nested, anonymous, and local classes.</p> - - - - - Annotation - Class - Enum - Interface - - - - false - - false - <b>Class:</b> number of local (i.e. not inherited) attributes in the class, including the attributes of its nested and local classes. - <p><strong>Class:</strong> number of local (i.e. not inherited) attributes in the class, including the attributes of its nested and local classes.</p> - - - - - Class - - - - true - - false - <b>Class:</b> number of local (i.e. not inherited) attributes in the class, including the attributes of its nested and local classes. - <p><strong>Class:</strong> number of local (i.e. not inherited) attributes in the class, including the attributes of its nested and local classes.</p> - - - - - Class - - - true @@ -6698,91 +4642,6 @@ - - - true - true - false - Size - - false - Total Number of Local Public Attributes - - - - 0 - 0 - - - - - true - - false - <b>Class:</b> number of local (i.e. not inherited) public attributes in the class, including the local public attributes of its nested, anonymous, and local classes. - <p><strong>Class, Structure, Interface:</strong> number of local (i.e. not inherited) public attributes in the class, including the local public attributes of its nested, anonymous, and local classes.</p> - - - - - Class - Interface - Structure - - - - true - - false - <b>Class:</b> number of local (i.e. not inherited) public attributes in the class, including the local public attributes of its nested, anonymous, and local classes. - <p><strong>Class, Structure:</strong> number of local (i.e. not inherited) public attributes in the class, including the generated ones backing public auto properties and also local public attributes of its nested and anonymous classes.</p> - - - - - Class - Component - Interface - Structure - - - - true - - false - <b>Class:</b> number of local (i.e. not inherited) public attributes in the class, including the local public attributes of its nested, anonymous, and local classes. - <p><strong>Class:</strong> number of local (i.e. not inherited) public attributes in the class, including the local public attributes of its nested, anonymous, and local classes.</p> - - - - - Annotation - Class - Enum - Interface - - - - false - - false - - - - - - - false - - false - - - - - Class - - - true @@ -7165,100 +5024,6 @@ - - - true - true - false - Size - - false - Total Number of Public Attributes - - - - 0 - 0 - - - - - true - - false - <b>Class:</b> number of public attributes in the class, including the inherited ones, as well as the inherited and local public attributes of its nested, anonymous, and local classes.<br><b>Package:</b> number of public attributes in the package, including the public attributes of its subpackages.<br><b>Component:</b> number of public attributes in the component, including the public attributes of its subcomponents. - <p><strong>Class, Structure, Union, Interface:</strong> number of public attributes in the class, including the inherited ones, as well as the inherited and local public attributes of its nested, anonymous, and local classes.</p> <p><strong>Namespace:</strong> number of public attributes in the namespace, including the public attributes of its subnamespaces.</p> <p><strong>Component:</strong> number of public attributes in the component, including the public attributes of its subcomponents.</p> - - - - - Class - Component - Interface - Namespace - Structure - Union - - - - true - - false - <b>Class:</b> number of public attributes in the class, including the inherited ones, as well as the inherited and local public attributes of its nested, anonymous, and local classes.<br><b>Package:</b> number of public attributes in the package, including the public attributes of its subpackages.<br><b>Component:</b> number of public attributes in the component, including the public attributes of its subcomponents. - <p><strong>Class, Structure:</strong> number of public attributes in the class, including the inherited ones and the generated ones backing public auto properties as well as the inherited and local public attributes of its nested and anonymous classes.</p> <p><strong>Namespace:</strong> number of public attributes in the namespace, including the public attributes of its subnamespaces.</p> <p><strong>Component:</strong> number of public attributes in the component, including the public attributes of its subcomponents.</p> - - - - - Class - Component - Interface - Namespace - Structure - - - - true - - false - <b>Class:</b> number of public attributes in the class, including the inherited ones, as well as the inherited and local public attributes of its nested, anonymous, and local classes.<br><b>Package:</b> number of public attributes in the package, including the public attributes of its subpackages.<br><b>Component:</b> number of public attributes in the component, including the public attributes of its subcomponents. - <p><strong>Class:</strong> number of public attributes in the class, including the inherited ones, as well as the inherited and local public attributes of its nested, anonymous, and local classes.</p> <p><strong>Package:</strong> number of public attributes in the package, including the public attributes of its subpackages.</p> <p><strong>Component:</strong> number of public attributes in the component, including the public attributes of its subcomponents.</p> - - - - - Annotation - Class - Component - Enum - Interface - Package - - - - false - - false - - - - - - - false - - false - - - - - Class - Component - Module - Package - - - true diff --git a/cl/LIM2Metrics/main.cpp b/cl/LIM2Metrics/main.cpp index a5d4516..b7d5917 100644 --- a/cl/LIM2Metrics/main.cpp +++ b/cl/LIM2Metrics/main.cpp @@ -39,7 +39,7 @@ #include "common/inc/Stat.h" #include "csi/inc/csi.h" #include "lim2graph/inc/Lim2GraphConverter.h" -#include "limmetrics/inc/LimMetrics.h" +#include #include "graphsupport/inc/CsvExporter.h" #include "graphsupport/inc/RulBuilder.h" @@ -204,7 +204,6 @@ int main(int argc, char *argv[]) { updateMemStat( &mem ); - // // LOAD FILTER // diff --git a/cl/LIM2Patterns/CMakeLists.txt b/cl/LIM2Patterns/CMakeLists.txt index 00ed3d3..a0bc634 100644 --- a/cl/LIM2Patterns/CMakeLists.txt +++ b/cl/LIM2Patterns/CMakeLists.txt @@ -1,22 +1,5 @@ set (PROGRAM_NAME LIM2Patterns) -# Add a ${TARGET_NAME} named custom copy target, which will copy the ${SOURCE} -# file to the ${DESTINATION}. -function (add_copy_custom_target_dir TARGET_NAME SOURCE DESTINATION) - add_custom_command ( - DEPENDS ${SOURCE} - MAIN_DEPENDENCY ${SOURCE} - OUTPUT ${DESTINATION} - COMMAND ${CMAKE_COMMAND} -E copy_directory ${SOURCE} ${DESTINATION} - COMMENT "Copying ${SOURCE} to ${DESTINATION}" - ) - add_custom_target ( - ${TARGET_NAME} - DEPENDS ${DESTINATION} - ) - set_target_properties (${TARGET_NAME} PROPERTIES FOLDER ${CMAKE_SUPPORT_FOLDER_NAME}) -endfunction() - set (SOURCES src/Helpers.cpp #src/Calculate/CreateCalculate.cpp @@ -122,28 +105,19 @@ add_copy_custom_target_dir(${PATTERNS_COPY_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/Pat # add python libs add_copy_custom_target_dir(${LIBS_COPY_NAME} ${CMAKE_CURRENT_BINARY_DIR}/Lib ${EXECUTABLE_OUTPUT_PATH}/Lib) -function (add_language_config LANG) - add_executable(${PROGRAM_NAME}_${LANG} ${SOURCES}) - add_dependencies(${PROGRAM_NAME}_${LANG} ${PATTERNS_COPY_NAME} ${LIBS_COPY_NAME} ${COLUMBUS_GLOBAL_DEPENDENCY}) - - # have to python.h manually because of pybind11 - target_include_directories(${PROGRAM_NAME}_${LANG} PUBLIC ${COLUMBUS_3RDPARTY_INSTALL_DIR}/include/python${PY_PYVERSION} ${CMAKE_CURRENT_SOURCE_DIR}/pybind11/include) - # preprocessor for building the embedding statically - target_compile_definitions(${PROGRAM_NAME}_${LANG} PUBLIC Py_NO_ENABLE_SHARED ) - # not using pybind11::embed or pybind11::pybind11 because that includes the python installed on the system, and not the python in the 3rdparty - target_link_libraries(${PROGRAM_NAME}_${LANG} limmetrics lim2graph lim graph graphsupport rul strtable common csi io yamlcpp python${PY_PYVERSION} ${COMMON_EXTERNAL_LIBRARIES}) - # host specific libraries - if (CMAKE_SYSTEM_NAME STREQUAL Windows) - target_link_libraries(${PROGRAM_NAME}_${LANG} version ws2_32) - else (CMAKE_SYSTEM_NAME STREQUAL Linux) - target_link_libraries(${PROGRAM_NAME}_${LANG} pthread dl util m) - endif () - set_schema_language_compiler_settings(${PROGRAM_NAME}_${LANG} ${LANG}) - set_visual_studio_project_folder(${PROGRAM_NAME}_${LANG} FALSE) -endfunction() +add_executable(${PROGRAM_NAME} ${SOURCES}) +add_dependencies(${PROGRAM_NAME} ${PATTERNS_COPY_NAME} ${LIBS_COPY_NAME} ${COLUMBUS_GLOBAL_DEPENDENCY}) -add_language_config(cpp) -add_language_config(java) -add_language_config(javascript) -add_language_config(python) -add_language_config(csharp) +# have to python.h manually because of pybind11 +target_include_directories(${PROGRAM_NAME} PUBLIC ${COLUMBUS_3RDPARTY_INSTALL_DIR}/include/python${PY_PYVERSION} ${CMAKE_CURRENT_SOURCE_DIR}/pybind11/include) +# preprocessor for building the embedding statically +target_compile_definitions(${PROGRAM_NAME} PUBLIC Py_NO_ENABLE_SHARED ) +# not using pybind11::embed or pybind11::pybind11 because that includes the python installed on the system, and not the python in the 3rdparty +target_link_libraries(${PROGRAM_NAME} limmetrics lim2graph lim graph graphsupport rul strtable common csi io yamlcpp python${PY_PYVERSION} ${COMMON_EXTERNAL_LIBRARIES}) +# host specific libraries +if (CMAKE_SYSTEM_NAME STREQUAL Windows) + target_link_libraries(${PROGRAM_NAME} version ws2_32) +else (CMAKE_SYSTEM_NAME STREQUAL Linux) + target_link_libraries(${PROGRAM_NAME} pthread dl util m) +endif () +set_visual_studio_project_folder(${PROGRAM_NAME} FALSE) diff --git a/cl/LIM2Patterns/inc/Conditions/PythonCondition.h b/cl/LIM2Patterns/inc/Conditions/PythonCondition.h index fb97674..edd1575 100644 --- a/cl/LIM2Patterns/inc/Conditions/PythonCondition.h +++ b/cl/LIM2Patterns/inc/Conditions/PythonCondition.h @@ -24,11 +24,17 @@ #include "Condition.h" #include +#ifdef __GNUC__ + #ifndef __clang__ + #pragma GCC visibility push(hidden) + #endif +#endif + + namespace py = pybind11; namespace columbus { namespace lim { namespace patterns { namespace conditions { - #pragma GCC visibility push(hidden) class PythonCondition : virtual public Condition { private: // \brief Stores the name of the pattern diff --git a/cl/LIM2Patterns/src/Helpers.cpp b/cl/LIM2Patterns/src/Helpers.cpp index 6af2ee0..3eb4910 100644 --- a/cl/LIM2Patterns/src/Helpers.cpp +++ b/cl/LIM2Patterns/src/Helpers.cpp @@ -1021,7 +1021,7 @@ namespace columbus { namespace lim { namespace patterns { graph::Node limToGraph(graph::Graph &inGraph, const columbus::lim::asg::base::Base& limNode) { graph::Node gNode = inGraph.findNode(lim2graph::VisitorGraphConverter::determineNodeName(limNode)); - if (gNode == graph::Graph::invalidNode) throw columbus::Exception("LIM2AntiPatternsVisitor::limToGraph", CMSG_EX_INVALD_GRAPH_NODE(limNode.getId())); + if (gNode == graph::Graph::invalidNode) throw columbus::Exception("LIM2AntiPatternsVisitor::limToGraph", CMSG_EX_INVALD_GRAPH_NODE(std::to_string(limNode.getId()))); return gNode; } diff --git a/cl/LIM2Patterns/src/LIM2Patterns.cpp b/cl/LIM2Patterns/src/LIM2Patterns.cpp index 2f3c980..1336f39 100644 --- a/cl/LIM2Patterns/src/LIM2Patterns.cpp +++ b/cl/LIM2Patterns/src/LIM2Patterns.cpp @@ -21,9 +21,9 @@ #include "../inc/LIM2Patterns.h" #include "../inc/Helpers.h" #include "../inc/PythonBinding.h" -#include #include #include +#include using namespace std; using namespace common; diff --git a/cl/MetricHunter/src/ThresholdReader.cpp b/cl/MetricHunter/src/ThresholdReader.cpp index 02157a2..3e1f889 100644 --- a/cl/MetricHunter/src/ThresholdReader.cpp +++ b/cl/MetricHunter/src/ThresholdReader.cpp @@ -151,7 +151,7 @@ XERCES_CPP_NAMESPACE_USE common::split(entity, ruleEntities, ','); entities.insert(ruleEntities.begin(), ruleEntities.end()); - + //There we create a temp object and push into the vector trs.push_back(Threshold(mid,relation,value, ruleEntities)); diff --git a/cl/OpenStaticAnalyzerCPP/CMakeLists.txt b/cl/OpenStaticAnalyzerCPP/CMakeLists.txt new file mode 100644 index 0000000..20421f2 --- /dev/null +++ b/cl/OpenStaticAnalyzerCPP/CMakeLists.txt @@ -0,0 +1,25 @@ +set (PROGRAM_NAME OpenStaticAnalyzerCPP) + +set (SOURCES + src/Task.cpp + src/main.cpp + + inc/messages.h + inc/Properties.h + inc/Task.h +) + +add_executable(${PROGRAM_NAME} ${SOURCES}) +add_dependencies(${PROGRAM_NAME} ${COLUMBUS_GLOBAL_DEPENDENCY}) +target_link_libraries(${PROGRAM_NAME} archivecpp lim controller graph graphsupport threadpool rul strtable common csi io ${COMMON_EXTERNAL_LIBRARIES}) +add_copy_next_to_the_binary_dependency(${PROGRAM_NAME} rules_cpp.csv) +set_visual_studio_project_folder(${PROGRAM_NAME} TRUE) + +if (APPLE) +find_library(corefoundation_lib CoreFoundation) +find_library(coreservices_lib CoreServices) +set(frameworks + ${coreservices_lib} + ${corefoundation_lib}) +target_link_libraries(${PROGRAM_NAME} ${frameworks}) +endif (APPLE) diff --git a/cl/OpenStaticAnalyzerCPP/inc/Properties.h b/cl/OpenStaticAnalyzerCPP/inc/Properties.h new file mode 100644 index 0000000..0108c5a --- /dev/null +++ b/cl/OpenStaticAnalyzerCPP/inc/Properties.h @@ -0,0 +1,140 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _OSACPP_CONTR_PROP_H_ +#define _OSACPP_CONTR_PROP_H_ + +#include +#include +#include + +enum WrapperMode { + WM_CL, + WM_GCC, + WM_CLANG +}; + + +typedef struct WrappedTool { + bool fullpath; + boost::filesystem::path wrappedToolName; + boost::filesystem::path wrapperToolName; +} WrappedTool; + +struct Properties : public columbus::controller::BaseProperties { + Properties() + : cloneGenealogy(false) + , cloneMinLines(-1) + , wrapperMode( +#ifdef _WIN32 + WM_CL +#else + WM_CLANG +#endif + ) + , csvSeparator(',') + , csvDecimalmark('.') + , cleanResults(-1) + , cleanProject(false) + , maxCan2LimThreads(0) + , runCppcheck(true) + , runClangTidy(true) + , runLimMetrics(true) + , runDCF(true) + , runFaultHunter(true) + , runMetricHunter(true) + , runUDM(false) + , runUDMExplicit(false) + , analysisOutputDir(".columbus_cpp") + , faultTolerantMode(true) + , runLIM2Patterns(true) + {} + + bool cloneGenealogy; // Create clone genealogy or no. + int cloneMinLines; + + WrapperMode wrapperMode; // The wrapper mode + std::string prefix; // The wrapped tool prefix which is given by the user + std::string postfix; // The wrapped tool postfix which is given by the user + std::string projectName; // The name of the project which is given by the user + + boost::filesystem::path startCurrentDir; // Absolute path of the current directory when the CAC was started + boost::filesystem::path toolchainDir; // Absolute path of the directory of the CA toolchain + boost::filesystem::path wrapperDir; // Absolute path of the directory of the wrapper inside the CA package + boost::filesystem::path wrapperBinDir; // Absolute path of the directory of the wrapper binaries inside the CA package + boost::filesystem::path wrapperToolsDir; // Absolute path of the directory of the wrapper tools inside the CA package + boost::filesystem::path toolsDir; // Absolute path of the directory of the tools inside the CA package + + boost::filesystem::path profileXML; + boost::filesystem::path rulesCSV; + + boost::filesystem::path resultsDir; // Absolute path of the result directory given by the user + boost::filesystem::path buildScript; // Absolute path of the build script given by the user + boost::filesystem::path currentDate; // The current date + boost::filesystem::path projectResultDir; // resultsDir / projectName / + boost::filesystem::path projectTimedResultDir; // projectResultDir / currentDate + boost::filesystem::path projectBaseDir; // Absolute path of the base directory given by the user + boost::filesystem::path tempDir; // Absolute path of the directory of the temporary files + boost::filesystem::path asgDir; // Absolute path of the directory of the asg files + boost::filesystem::path graphDir; // Absolute path of the directory of the graph files + boost::filesystem::path columbusWrapperTmpDir; // Absolute path of the directory where the wrapper is assembled + boost::filesystem::path columbusWrapperTmpDirName; // Name of the directory where the wrapper is assembled (smDir / temp / wrapper) + boost::filesystem::path externalHardFilter; // Absolute path of the external hardfilter file + boost::filesystem::path externalSoftFilter; // Absolute path of the external softfilter file + char csvSeparator; // Column separator character of the csv outputs. + char csvDecimalmark; // Decimal mark character in the csv outputs. + std::string sarifSeverityLevel; // Severity level to be converted into sarif + int cleanResults; // Keep the last 'cleanResults' number of timestamped directory of the project in the results. + bool cleanProject; // Removes all files created outside the results directory during previous analyses, but does not remove anything from the results directory. + bool analyzeOnly; // Run the analysis only. + int maxCan2LimThreads; // Number of maximum threads the Can2Lim task can use + bool runCppcheck; // Run cppcheck. + bool runClangTidy; // Run clang-tidy. + bool runLimMetrics; // Run Lim2Metrics. + bool runDCF; // Run DCF. + bool runFaultHunter; // Run FaultHunter. + bool runMetricHunter; // Run MetricHunter. + bool runUDM; // Run UserDefinedMetrics + bool runUDMExplicit; // Was the "runUDM" switch explicitly set on the command line? + std::string analysisOutputDir; // The name of the output directory (.columbus_cpp) + bool faultTolerantMode; // Fault tolerant mode + + bool runSonar2Graph; // Run Sonar2Graph tool to extrat issues from SonarQube server. + std::string host; // IP of the SonarQube server. + std::string port; // Port of the SonarQube server. + std::string projectKey; // Key of the project on the SonarQube server. + std::string projectPrefix; // Prefix path of the project's base directory. + std::string jsonPath; // For testing only. + std::string sqUsername; // Username for the SonarQube server. + std::string sqPassword; // Password for the SonarQube server. + std::string languageKey; // Key of the language in SonarQube. + bool sonar2GraphVerbose; // Prints more information about the running of Sonar2Graph tool. + bool strict; // If true, the tool will stop working if finds too many issues in one file. + bool noDelayedTemplateParsing; // If true, -fno-delayed-template-parsing will be passed to the CAN. + + bool runLIM2Patterns; // Run LIM2Patterns + std::string patternFile; // Location of the pattern file + std::string whitelist; // Pattern whitelist, can be set from profileXML + std::string blacklist; // Pattern blacklist, can be set from profileXML +}; + +extern Properties props; + +#endif diff --git a/cl/OpenStaticAnalyzerCPP/inc/Task.h b/cl/OpenStaticAnalyzerCPP/inc/Task.h new file mode 100644 index 0000000..396eee6 --- /dev/null +++ b/cl/OpenStaticAnalyzerCPP/inc/Task.h @@ -0,0 +1,109 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _OSACPP_CONTR_TASK_H_ +#define _OSACPP_CONTR_TASK_H_ + +#include +#include + +#include "Properties.h" +#include +#include + + +DEFINETASK(CleanupTask) +DEFINETASK(Can2limTask) +DEFINETASK(ProfileTask) +DEFINETASK(Cppcheck2GraphTask) +DEFINETASK(Lim2metricsTask) +DEFINETASK(DcfTask) +DEFINETASK(Lim2umlTask) +DEFINETASK(GraphMergeTask) +DEFINETASK(GraphDumpTask) +DEFINETASK(CleanResultsTask) +DEFINETASK(CleanProjectTask) +DEFINETASK(MetricHunterTask) +DEFINETASK(LinkStaticLibsTask) +DEFINETASK(StaticLibHandlerTask) +DEFINETASK(Sonar2GraphTask) +DEFINETASK(LIM2PatternsTask) + +class ClangTidyTask : public columbus::controller::Task +{ + class Worker : public columbus::thread::Task + { + public: + Worker(const boost::filesystem::path program, std::queue>& clangtidy_args, std::string& logDir, boost::mutex& m, boost::condition_variable& cv, std::atomic& threadsLeft, int* failure) : program(program), clangtidy_args(clangtidy_args), logDir(logDir), m(m), cv(cv), threadsLeft(threadsLeft), failure(failure) {} + void operator()(); + + private: + const boost::filesystem::path program; + std::queue>& clangtidy_args; + std::string logDir; + boost::mutex& m; + boost::condition_variable& cv; + std::atomic& threadsLeft; + int* failure; + }; + +public: + ClangTidyTask(const Properties& properties, columbus::thread::ThreadPool& threadPool); + virtual ExecutionResult execute(); + + const static std::string name; + virtual const std::string& getName() const { + return name; + } + +private: + columbus::thread::ThreadPool& threadPool; + + friend class Worker; +}; + +class WrapperTask : public columbus::controller::Task +{ +public: + WrapperTask(const Properties& properties); + virtual ExecutionResult execute(); + + void wrapTool(const std::string& wrappedTool, const std::string& wrapperTool, std::vector& sv ) const; + + const static std::string name; + virtual const std::string& getName() const{ + return name; + } +}; + +class UserDefinedMetricsTask : public columbus::controller::Task +{ +private: + std::list& inactives; +public: + const static std::string name; + UserDefinedMetricsTask(std::list& inactives, const Properties& properties); + virtual ExecutionResult execute(); + virtual const std::string& getName() const { + return name; + } +}; + +#endif diff --git a/cl/OpenStaticAnalyzerCPP/inc/messages.h b/cl/OpenStaticAnalyzerCPP/inc/messages.h new file mode 100644 index 0000000..ee510ee --- /dev/null +++ b/cl/OpenStaticAnalyzerCPP/inc/messages.h @@ -0,0 +1,44 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _OSACPP_CONTR_M_H_ +#define _OSACPP_CONTR_M_H_ + +#define CMSG_ERROR_CREATE_DIR "ERROR: Can't create %s dir.\n" +#define CMSG_CANNOT_OPEN_LCSI_FOR_WRITING "WARNING: Can't open lcsi list file for writing!" +#define CMSG_TOO_SHORT_ACSI_NAME "WARNING: The name of the acsi file is to short!" +#define CMSG_ERROR_DELETE_DIR "ERROR: Can't delete %s dir. %s.\n" +#define CMSG_WRAPPER_ERROR "ERROR: During the analysis at least one of the wrappers has reported error! For further details please check the openstaticanalyzer/temp/wrapper/log/wraplog.log file in the results directory." +#define CMSG_CAN_NOT_CREATE_RM_WRAPPER_ERROR "ERROR: Can't create 'rm' wrapper file!" +#define CMSG_NO_OUTPUT_ERROR "ERROR: During the analysis neither linked component nor static library has been created! Please check the environment and the build script to be sure that the compiler tools can be wrapped and at least one linking phase (or static library creation) is executed during the build process!" + + +#define CMSG_UNSUPPORTED_LINKING_MODE WriteMsg::mlError, "ERROR: The Linking mode 2 is not supported yet!\n" +#define CMSG_BAD_LINKING_MODE WriteMsg::mlError, "ERROR: Only linking mode 1,2 and 3 are valid!\n" +#define CMSG_WARNING_FILE_MISSING WriteMsg::mlWarning, "WARNING: The '%s' file is missing!\n" + +#define CMSG_ENV_VAR_SET_ERROR WriteMsg::mlError, "ERROR: Failed to set '%s' environment variable!\n" + +#define CMSG_SUCCESSFUL_TERMINATION WriteMsg::mlNormal, "Done!" +#define CMSG_FAILURE_TERMINATION WriteMsg::mlNormal, "Failed!" + +#define CMSG_FAILED_TO_OPEN_FILE WriteMsg::mlError, "File %s can't be opened!\n" + +#endif diff --git a/cl/OpenStaticAnalyzerCPP/rules_cpp.csv b/cl/OpenStaticAnalyzerCPP/rules_cpp.csv new file mode 100644 index 0000000..5ab424f --- /dev/null +++ b/cl/OpenStaticAnalyzerCPP/rules_cpp.csv @@ -0,0 +1,738 @@ +toolId;CPPCHECK;CT +AATI;1;- +ABTF;1;- +ABTP;1;- +AF;1;- +AIA;1;- +AID;1;- +AIE;1;- +AIOOB;1;- +AIOOBC;1;- +AITA;1;- +AITC;1;- +AM;1;- +AOOVP;1;- +AOSBLU;1;- +AS;1;- +AV;1;- +AVAGP;1;- +AWSE;1;- +BAOOB;1;- +BBC;1;- +BFE;1;- +BNZT;1;- +BOB;1;- +CAF;1;- +CAI;1;- +CATIAR;1;- +CBEWI;1;- +CBO;1;- +CCAEO;1;- +CCALC;1;- +CCITCAB;1;- +CCM;1;- +CCOND;1;- +CCPC;1;- +CE;1;- +CEBV;1;- +CFIATOF;1;- +CIODC1;1;- +CIODC2;1;- +CITAAR;1;- +CLWCPC;1;- +CNC;1;- +COBWBE;1;- +COBWIC;1;- +COFRBE;1;- +COOB;1;- +COTFRBE;1;- +CS;1;- +CSC;1;- +CSR;1;- +CSTAT;1;- +DAE;1;- +DAR;1;- +DBRANCH;1;- +DBREAK;1;- +DD;1;- +DET;1;- +DEXPR;1;- +DF;1;- +DII;1;- +DIM;1;- +DL;1;- +DP;1;- +DSO;1;- +DU;1;- +DUOS;1;- +DVT;1;- +ED;1;- +EDT;1;- +ERC;1;- +ETID;1;- +FAND;1;- +FAOD;1;- +FC;1;- +FCO;1;- +FOIS;1;- +FS;1;- +IAF;1;- +IB;1;- +ICAEE;1;- +ICBE;1;- +ICLA;1;- +IF;1;- +IFA;1;- +IFAB;1;- +IFAS;1;- +IIC;1;- +IIT;1;- +IIT2;1;- +IL;1;- +ILME;1;- +ILO;1;- +ILT;1;- +IO;1;- +IOWP;1;- +IP;1;- +IPATF;1;- +IPATN;1;- +IPATP;1;- +IPATS;1;- +IPATSI;1;- +IPATUI;1;- +IPC;1;- +IRV;1;- +IS;1;- +ISATF;1;- +ISATI;1;- +ISATS;1;- +ISBE;1;- +ISC;1;- +ISFW;1;- +ITFO;1;- +LNVFC;1;- +LRVNU;1;- +MAD;1;- +MATF;1;- +MBA;1;- +MC;1;- +MCE;1;- +MCF;1;- +MCOND;1;- +MCR;1;- +MF;1;- +MI;1;- +ML;1;- +MMC;1;- +MO;1;- +MOCE;1;- +MOCW;1;- +MOR;1;- +MRFAO;1;- +MS;1;- +MSI;1;- +MSO;1;- +MVOOR;1;- +MZB;1;- +NAO;1;- +NAS;1;- +NC;1;- +NCC;1;- +ND;1;- +NEC;1;- +NI;1;- +NIAE;1;- +NMAS;1;- +NP;1;- +NPDWDA;1;- +OE;1;- +OERRT;1;- +OETS;1;- +OEVE;1;- +OIC;1;- +OOB;1;- +OPE;1;- +OS;1;- +PAB;1;- +PAE;1;- +PANC;1;- +PAWN;1;- +PBAOOB;1;- +PBV;1;- +PC;1;- +PED;1;- +PLTZ;1;- +PO;1;- +POOB;1;- +PP;1;- +PS;1;- +PVC;1;- +RA;1;- +RAID;1;- +RAIS;1;- +RAOAV;1;- +RAOFP;1;- +RBOIS;1;- +RCIS;1;- +RCLC;1;- +RCOND;1;- +RCPY;1;- +RDL;1;- +REC;1;- +RF;1;- +RIR;1;- +RL;1;- +RLV;1;- +RNBIBF;1;- +RNPC;1;- +RPO;1;- +RTF;1;- +RWOF;1;- +SA;1;- +SAAC;1;- +SBN;1;- +SC;1;- +SCAI;1;- +SCP;1;- +SCR;1;- +SCT;1;- +SEC;1;- +SF;1;- +SI;1;- +SIE;1;- +SIWDC1;1;- +SIWDC2;1;- +SLW;1;- +SN;1;- +SOAF;1;- +SOC;1;- +SOD;1;- +SODMF;1;- +SODVP;1;- +SOFC;1;- +SOSO;1;- +SOV;1;- +SOWNP;1;- +SOWSAP;1;- +SPC;1;- +SS;1;- +SSC;1;- +STLB;1;- +STLC;1;- +STLIF;1;- +STLISF;1;- +STLMC;1;- +STLOOB;1;- +STLS;1;- +STMB;1;- +STMBS;1;- +STRCMP;1;- +STRCU;1;- +SUSPC;1;- +SV;1;- +TINF;1;- +TLCA;1;- +TLCR;1;- +TMC;1;- +TS;1;- +TSTRC;1;- +UA;1;- +UAA;1;- +UAPA;1;- +UAPARG;1;- +UAPC;1;- +UAPCPY;1;- +UAPM;1;- +UAV;1;- +UCC;1;- +UCCDBZ;1;- +UCCL;1;- +UCE;1;- +UCF;1;- +UCR;1;- +UCS;1;- +UCSS;1;- +UEO;1;- +UES;1;- +UID;1;- +UIL;1;- +UISM;1;- +UIV;1;- +UL;1;- +ULTZ;1;- +UMV;1;- +UP;1;- +UPF;1;- +UPMC;1;- +URC;1;- +URV;1;- +USA;1;- +USL;1;- +UUAM;1;- +UUF;1;- +UUSM;1;- +UUSO;1;- +UUV;1;- +VAEM;1;- +VALUBS;1;- +VASRP;1;- +VASSC;1;- +VASWP;1;- +VCIC;1;- +VCWSL;1;- +VD;1;- +VFNUB;1;- +VS;1;- +WMC;1;- +WPPS;1;- +WPSAN;1;- +WPSPPE;1;- +WROF;1;- +ZD;1;- +ZDC;1;- +ABS_DA;-;1 +ABS_DC;-;1 +ABS_DCC;-;1 +ABS_DD;-;1 +ABS_DFF;-;1 +ABS_DFS;-;1 +ABS_DS;-;1 +ABS_DUC;-;1 +ABS_FSD;-;1 +ABS_NID;-;1 +ABS_NN;-;1 +ABS_RSC;-;1 +ABS_SCA;-;1 +ABS_SFS;-;1 +ABS_SFSC;-;1 +ABS_TC;-;1 +ABS_TS;-;1 +ABS_UDC;-;1 +ALT_KNR;-;1 +ALT_SPA;-;1 +ALT_SWIB;-;1 +AND_CA;-;1 +AND_CA2;-;1 +AND_CC;-;1 +AND_CD;-;1 +AND_CEC;-;1 +AND_CEC2;-;1 +AND_CF;-;1 +AND_CII;-;1 +AND_CII2;-;1 +AND_CITFR;-;1 +AND_CMC;-;1 +AND_CO;-;1 +AND_CP;-;1 +AND_CP2;-;1 +AND_CS;-;1 +BST_UTS;-;1 +BUG_AC;-;1 +BUG_ASE;-;1 +BUG_BC;-;1 +BUG_BPIC;-;1 +BUG_BSTKT;-;1 +BUG_CCI;-;1 +BUG_DH;-;1 +BUG_DSI;-;1 +BUG_EE;-;1 +BUG_FDN;-;1 +BUG_FIT;-;1 +BUG_FRO;-;1 +BUG_ID;-;1 +BUG_IE;-;1 +BUG_IL;-;1 +BUG_IR;-;1 +BUG_LFN;-;1 +BUG_MFR;-;1 +BUG_MOISIA;-;1 +BUG_MP;-;1 +BUG_MPAIA;-;1 +BUG_MRSE;-;1 +BUG_MSM;-;1 +BUG_MWC;-;1 +BUG_NC;-;1 +BUG_NE;-;1 +BUG_NNTR;-;1 +BUG_PR;-;1 +BUG_PVC;-;1 +BUG_RBC;-;1 +BUG_RI;-;1 +BUG_SA;-;1 +BUG_SC;-;1 +BUG_SC2;-;1 +BUG_SCM;-;1 +BUG_SE;-;1 +BUG_SEU;-;1 +BUG_SH;-;1 +BUG_SI;-;1 +BUG_SIA;-;1 +BUG_SLWEN;-;1 +BUG_SMC;-;1 +BUG_SMU;-;1 +BUG_SS;-;1 +BUG_SSC;-;1 +BUG_SWUF;-;1 +BUG_TC;-;1 +BUG_TKM;-;1 +BUG_TSLV;-;1 +BUG_UAM;-;1 +BUG_UC;-;1 +BUG_UMM;-;1 +BUG_UR;-;1 +BUG_URV;-;1 +BUG_USA;-;1 +BUG_VNM;-;1 +CON_MU;-;1 +CPP_ACA;-;1 +CPP_AG;-;1 +CPP_AMN;-;1 +CPP_ANCGV;-;1 +CPP_CCAS;-;1 +CPP_EVF;-;1 +CPP_IGI;-;1 +CPP_IV;-;1 +CPP_MU;-;1 +CPP_NC;-;1 +CPP_NM;-;1 +CPP_NPMVIC;-;1 +CPP_OM;-;1 +CPP_PBATPD;-;1 +CPP_PBCAI;-;1 +CPP_PBPA;-;1 +CPP_PMI;-;1 +CPP_PTCC;-;1 +CPP_PTCC2;-;1 +CPP_PTMI;-;1 +CPP_PTRC;-;1 +CPP_PTSCD;-;1 +CPP_PTUA;-;1 +CPP_PTV;-;1 +CPP_S;-;1 +CPP_SMF;-;1 +CRT_CON36_C;-;1 +CRT_CON54_CPP;-;1 +CRT_DCL03_C;-;1 +CRT_DCL16_C;-;1 +CRT_DCL21_CPP;-;1 +CRT_DCL37_C;-;1 +CRT_DCL50_CPP;-;1 +CRT_DCL51_CPP;-;1 +CRT_DCL54_CPP;-;1 +CRT_DCL58_CPP;-;1 +CRT_DCL59_CPP;-;1 +CRT_ENV33_C;-;1 +CRT_ERR09_CPP;-;1 +CRT_ERR34_C;-;1 +CRT_ERR52_CPP;-;1 +CRT_ERR58_CPP;-;1 +CRT_ERR60_CPP;-;1 +CRT_ERR61_CPP;-;1 +CRT_FIO38_C;-;1 +CRT_FLP30_C;-;1 +CRT_MEM57_CPP;-;1 +CRT_MSC30_C;-;1 +CRT_MSC32_C;-;1 +CRT_MSC50_CPP;-;1 +CRT_MSC51_CPP;-;1 +CRT_OOP11_CPP;-;1 +CRT_OOP54_CPP;-;1 +CRT_OOP57_CPP;-;1 +CRT_OOP58_CPP;-;1 +CRT_POS44_C;-;1 +CRT_SIG30_C;-;1 +CRT_STR34_C;-;1 +DRW_AS;-;1 +DRW_DON;-;1 +FCS_DAC;-;1 +FCS_DAD;-;1 +FCS_HAN;-;1 +FCS_MI;-;1 +FCS_OO;-;1 +FCS_SCO;-;1 +FCS_TR;-;1 +FCS_VI;-;1 +GGL_BEMP;-;1 +GGL_BN;-;1 +GGL_BUN;-;1 +GGL_DA;-;1 +GGL_EC;-;1 +GGL_GNIH;-;1 +GGL_OANN;-;1 +GGL_OATE;-;1 +GGL_OFN;-;1 +GGL_OGVD;-;1 +GGL_RAUIGN;-;1 +GGL_RBAS;-;1 +GGL_RC;-;1 +GGL_RFS;-;1 +GGL_RI;-;1 +GGL_RNC;-;1 +GGL_RO;-;1 +GGL_RT;-;1 +GGL_UGC;-;1 +HIC_ACA;-;1 +HIC_AG;-;1 +HIC_BAS;-;1 +HIC_DH;-;1 +HIC_EB;-;1 +HIC_EC;-;1 +HIC_FS;-;1 +HIC_IAM;-;1 +HIC_MCA;-;1 +HIC_MI;-;1 +HIC_MPC;-;1 +HIC_NA;-;1 +HIC_NAD;-;1 +HIC_NDO;-;1 +HIC_NM;-;1 +HIC_NM2;-;1 +HIC_NP;-;1 +HIC_SA;-;1 +HIC_SB;-;1 +HIC_SMF;-;1 +HIC_UA;-;1 +HIC_UC;-;1 +HIC_UE;-;1 +HIC_UED;-;1 +HIC_UED2;-;1 +HIC_ULS;-;1 +HIC_UN;-;1 +HIC_UN2;-;1 +HIC_UO;-;1 +HIC_V;-;1 +KRN_MCE;-;1 +LLC_CN;-;1 +LLC_IIN;-;1 +LLC_RSLH;-;1 +LLV_EAR;-;1 +LLV_HG;-;1 +LLV_IO;-;1 +LLV_NC;-;1 +LLV_PIODCIC;-;1 +LLV_PROU;-;1 +LLV_QA;-;1 +LLV_TL;-;1 +MDR_AB;-;1 +MDR_ACA;-;1 +MDR_CNN;-;1 +MDR_DH;-;1 +MDR_DIBA;-;1 +MDR_LC;-;1 +MDR_MS;-;1 +MDR_MU;-;1 +MDR_PBV;-;1 +MDR_RAP;-;1 +MDR_RBIL;-;1 +MDR_RDCAAM;-;1 +MDR_RRS;-;1 +MDR_RSL;-;1 +MDR_RVA;-;1 +MDR_STF;-;1 +MDR_UA;-;1 +MDR_UBL;-;1 +MDR_UDMI;-;1 +MDR_UE;-;1 +MDR_UED;-;1 +MDR_UED2;-;1 +MDR_UN;-;1 +MDR_UN2;-;1 +MDR_UN3;-;1 +MDR_UO;-;1 +MDR_USA;-;1 +MDR_UTF;-;1 +MDR_UTRT;-;1 +MDR_UU;-;1 +MDR_UUE;-;1 +MPI_BD;-;1 +MPI_TM;-;1 +MSC_CEBR;-;1 +MSC_DIH;-;1 +MSC_HP;-;1 +MSC_MC;-;1 +MSC_MVDUD;-;1 +MSC_MVDUN;-;1 +MSC_NCO;-;1 +MSC_NDO;-;1 +MSC_NPIFCT;-;1 +MSC_NPMVIC;-;1 +MSC_NR;-;1 +MSC_RE;-;1 +MSC_SA;-;1 +MSC_SA2;-;1 +MSC_SAIAO;-;1 +MSC_SDANSIH;-;1 +MSC_SNIP;-;1 +MSC_TBVCBR;-;1 +MSC_UAD;-;1 +MSC_UAO;-;1 +MSC_UP;-;1 +MSC_URR;-;1 +MSC_UUD;-;1 +OBC_ANI;-;1 +OBC_DIC;-;1 +OBC_FS;-;1 +OBC_MH;-;1 +OBC_NAL;-;1 +OBC_PD;-;1 +OBC_SS;-;1 +OMP_EE;-;1 +OMP_UDN;-;1 +PRF_FRC;-;1 +PRF_FSF;-;1 +PRF_IA;-;1 +PRF_ICIL;-;1 +PRF_ISC;-;1 +PRF_IVO;-;1 +PRF_MCA;-;1 +PRF_MCI;-;1 +PRF_NAM;-;1 +PRF_NITP;-;1 +PRF_NMC;-;1 +PRF_TD;-;1 +PRF_TPIMF;-;1 +PRF_UCI;-;1 +PRF_UVP;-;1 +PRT_RSI;-;1 +PRT_SI;-;1 +RDB_ACPID;-;1 +RDB_BAS;-;1 +RDB_CMFTS;-;1 +RDB_CRT;-;1 +RDB_CSE;-;1 +RDB_DD;-;1 +RDB_DNP;-;1 +RDB_EAR;-;1 +RDB_FCC;-;1 +RDB_FS;-;1 +RDB_IBC;-;1 +RDB_ID;-;1 +RDB_IDPN;-;1 +RDB_IN;-;1 +RDB_MAI;-;1 +RDB_MI;-;1 +RDB_MMFC;-;1 +RDB_MN;-;1 +RDB_NCP;-;1 +RDB_NP;-;1 +RDB_QA;-;1 +RDB_RAS;-;1 +RDB_RCF;-;1 +RDB_RD;-;1 +RDB_RFPD;-;1 +RDB_RMI;-;1 +RDB_RP;-;1 +RDB_RSC;-;1 +RDB_RSG;-;1 +RDB_RSI;-;1 +RDB_SATI;-;1 +RDB_SBE;-;1 +RDB_SC;-;1 +RDB_SDIAN;-;1 +RDB_SSE;-;1 +RDB_UA;-;1 +RDB_UDR;-;1 +RDB_ULS;-;1 +SA_BLT_BF;-;1 +SA_BLT_NRF;-;1 +SA_COR_CAM;-;1 +SA_COR_DTP;-;1 +SA_COR_DZ;-;1 +SA_COR_ND;-;1 +SA_COR_NNPC;-;1 +SA_COR_NNSC;-;1 +SA_COR_SAE;-;1 +SA_COR_SAEB;-;1 +SA_COR_UBOR;-;1 +SA_COR_VS;-;1 +SA_CPP_IP;-;1 +SA_CPP_M;-;1 +SA_CPP_ND;-;1 +SA_CPP_NDL;-;1 +SA_CPP_PNC;-;1 +SA_CPP_PVC;-;1 +SA_CPP_SA;-;1 +SA_DCD_DS;-;1 +SA_FCS_HC;-;1 +SA_NUL_NB;-;1 +SA_NUL_ND;-;1 +SA_NUL_NPTN;-;1 +SA_NUL_NPTN2;-;1 +SA_NUL_NRFN;-;1 +SA_NUL_NRFN2;-;1 +SA_OI_CPP_UO;-;1 +SA_OI_CPP_VC;-;1 +SA_OI_MPI_M;-;1 +SA_OI_OSX_LOC_ELCC;-;1 +SA_OI_OSX_LOC_NLSC;-;1 +SA_OI_OSX_OCC;-;1 +SA_OI_PRF_GA;-;1 +SA_OI_PRF_P;-;1 +SA_OI_PRT_UA;-;1 +SA_OSX_A;-;1 +SA_OSX_CCA_AS;-;1 +SA_OSX_CCA_AW;-;1 +SA_OSX_CCA_CR;-;1 +SA_OSX_CCA_D;-;1 +SA_OSX_CCA_IMT;-;1 +SA_OSX_CCA_L;-;1 +SA_OSX_CCA_MSC;-;1 +SA_OSX_CCA_NA;-;1 +SA_OSX_CCA_NAP;-;1 +SA_OSX_CCA_NE;-;1 +SA_OSX_CCA_NNRV;-;1 +SA_OSX_CCA_OCG;-;1 +SA_OSX_CCA_RC;-;1 +SA_OSX_CCA_RCB;-;1 +SA_OSX_CCA_RLAL;-;1 +SA_OSX_CCA_SD;-;1 +SA_OSX_CCA_SI;-;1 +SA_OSX_CCA_UI;-;1 +SA_OSX_CCA_VMT;-;1 +SA_OSX_CRF_CE;-;1 +SA_OSX_CRF_CN;-;1 +SA_OSX_CRF_CRR;-;1 +SA_OSX_CRF_OOB;-;1 +SA_OSX_CRF_PSV;-;1 +SA_OSX_MIGCC;-;1 +SA_OSX_NOC;-;1 +SA_OSX_NOCEDC;-;1 +SA_OSX_OCP;-;1 +SA_OSX_ORC;-;1 +SA_OSX_SKA;-;1 +SA_SEC_B;-;1 +SA_SEC_B2;-;1 +SA_SEC_B3;-;1 +SA_SEC_DOUBH;-;1 +SA_SEC_DVOOT;-;1 +SA_SEC_FLC;-;1 +SA_SEC_G;-;1 +SA_SEC_G2;-;1 +SA_SEC_M;-;1 +SA_SEC_M2;-;1 +SA_SEC_R;-;1 +SA_SEC_S;-;1 +SA_SEC_SSC;-;1 +SA_SEC_UR;-;1 +SA_SEC_V;-;1 +SA_UIN_A;-;1 +SA_UIN_AS;-;1 +SA_UIN_B;-;1 +SA_UIN_CBV;-;1 +SA_UIN_UR;-;1 +SA_UNX_A;-;1 +SA_UNX_BSA;-;1 +SA_UNX_M;-;1 +SA_UNX_MD;-;1 +SA_UNX_MS;-;1 +SA_UNX_NA;-;1 +SA_UNX_V;-;1 +SA_VAL_CTS;-;1 +SA_VAL_U;-;1 +SA_VAL_U2;-;1 +SA_VAL_VB;-;1 +SA_WBK_NUMC;-;1 +SA_WBK_RCBVD;-;1 +SA_WBK_ULCC;-;1 +ZRC_TO;-;1 diff --git a/cl/OpenStaticAnalyzerCPP/src/Task.cpp b/cl/OpenStaticAnalyzerCPP/src/Task.cpp new file mode 100644 index 0000000..50e5e60 --- /dev/null +++ b/cl/OpenStaticAnalyzerCPP/src/Task.cpp @@ -0,0 +1,1230 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include +#include +#include // std::string +#include // std::stringstream +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../inc/Task.h" +#include "../inc/messages.h" +#include "../inc/Properties.h" + +using namespace std; +using namespace columbus; +using namespace columbus::controller; +using namespace common; +using namespace boost::filesystem; + +namespace +{ + void generateClangTidyConfigFile(columbus::rul::RulHandler& rulHandler, const std::string& outputFileName); + list archives; +} + + +TASK_NAME_DEF (CleanupTask); + +Task::ExecutionResult CleanupTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + + try { + // Although the desctructor will be called during the program termination we + // invoke it here just to remove them as soon as possible + logstream << "Removing the contents of the temporarily extracted archives.\n"; + archives.clear(); + + path wrapperbin(LONGDIRPREFIXSTRING + (props.columbusWrapperTmpDir / "bin").wstring()); + logstream << "Removing directory: " << wrapperbin.string() << "\n"; + + boost::system::error_code errorcode; + for(int i=0; i<3; i++){ + remove_all(wrapperbin, errorcode); + if(errorcode.value() == boost::system::errc::success) + break; + } + + logger.warningIfFail( errorcode.value() == boost::system::errc::success, "Failed to remove wrapper bin directory. %s.\n", errorcode.message().c_str()); + + } HANDLE_TASK_EXCEPTIONS + return result; +} + +CleanupTask::CleanupTask(const Properties& properties) : Task(properties) +{ + addDependsOn(GraphMergeTask::name); +} + +TASK_NAME_DEF( CleanProjectTask); + +Task::ExecutionResult CleanProjectTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + + try { + + if(exists(props.projectBaseDir) && is_directory(props.projectBaseDir)){ + + recursive_directory_iterator it(props.projectBaseDir); + recursive_directory_iterator endit; + + list folderList; + + while(it != endit) + { + if(is_directory(*it) && it->path().filename() == props.analysisOutputDir) { + folderList.push_back(it->path()); + } + ++it; + } + for(list::iterator folder = folderList.begin(); folder != folderList.end(); ++folder){ + logstream << "Removing directory: " << folder->string() << endl; + remove_all(*folder); + } + } + + } HANDLE_TASK_EXCEPTIONS + return result; +} + +CleanProjectTask::CleanProjectTask(const Properties& properties) : Task(properties) +{ + addDependsOn(Can2limTask::name); + addDependsOn(GraphDumpTask::name); +} + + + +TASK_NAME_DEF(WrapperTask); + +Task::ExecutionResult WrapperTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + + try { + path wrapperWorkDir = props.columbusWrapperTmpDir; + path wrapperWorkDirBin = wrapperWorkDir / "bin"; // These directories are used in the LinkStaticLibsTask as well + path wrapperWorkDirLog = wrapperWorkDir / "log"; + path wrapperWorkDirTmp = wrapperWorkDir / "tmp"; + path wrapperWorkDirLib = wrapperWorkDir / "lib"; + + createDirectories(wrapperWorkDirBin, logger); + createDirectories(wrapperWorkDirLog, logger); + createDirectories(wrapperWorkDirTmp, logger); + createDirectories(wrapperWorkDirLib, logger); + + copyBinaryExecutable(props.wrapperToolsDir, wrapperWorkDirBin, "CAN"); + copyBinaryExecutable(props.wrapperToolsDir, wrapperWorkDirBin, "CANConfig"); + copyBinaryExecutable(props.wrapperToolsDir, wrapperWorkDirBin, "CANLink"); + copyBinaryExecutable(props.wrapperToolsDir, wrapperWorkDirBin, "CANLib"); + copyBinaryExecutable(props.wrapperToolsDir, wrapperWorkDirBin, "AnalyzerWrapperConfig"); + + copyDirectory(props.wrapperToolsDir, wrapperWorkDirBin, "cppcheck"); + copyDirectory(props.wrapperToolsDir, wrapperWorkDirLib, "clang"); + + SafeEnvironmentModifier wwd_env("WRAPPER_WORK_DIR", wrapperWorkDir, logger); + SafeEnvironmentModifier wbd_env("WRAPPER_BIN_DIR", wrapperWorkDirBin, logger); + SafeEnvironmentModifier wld_env("WRAPPER_LOG_DIR", wrapperWorkDirLog, logger); + SafeEnvironmentModifier wtd_env("WRAPPER_TEMP_DIR", wrapperWorkDirTmp, logger); + SafeEnvironmentModifier we_env("WRAPPER_ENVIRONMENT", props.tempDir, logger); + SafeEnvironmentModifier wwdn_env("WRAPPER_WORK_DIR_NAME", props.columbusWrapperTmpDirName, logger); + + // ------------------------------------------------------------------------------------------------------------- + // --------------------------------------- WrapperEnvironmentConfig -------------------------------------------- + // ------------------------------------------------------------------------------------------------------------- + + path wrapperEnvironmentConfigPath = wrapperWorkDir / "wrapper_environment_config.ini"; + + vector sv; + + if (props.wrapperMode == WM_CL) + { + wrapTool("cl.exe", "CLWrapper.exe", sv); + wrapTool("link.exe", "LinkWrapper.exe", sv); + wrapTool("lib.exe", "LibWrapper.exe", sv); + wrapTool("clang-cl.exe","CLWrapper.exe",sv); + wrapTool("lld-link.exe","LinkWrapper.exe",sv); + wrapTool("llvm-lib.exe","LibWrapper.exe",sv); + + copy_file(props.wrapperBinDir/"VsbuildWrapper.exe", wrapperWorkDirBin / "msbuild.exe"); + copy_file(props.wrapperBinDir/"VsbuildWrapper.exe", wrapperWorkDirBin / "devenv.exe"); + } + else if (props.wrapperMode == WM_CLANG) + { + string clangTool = props.prefix + "clang" + props.postfix; + string clangppTool = props.prefix + "clang++" + props.postfix; + string arTool = props.prefix + "ar"; + string ldTool = props.prefix + "ld"; + string lnTool = props.prefix + "ln"; + string llvmarTool = "llvm-ar"; + string llvmldTool = "ld.lld"; + + + wrapTool(clangTool,"ClangWrapper",sv); + wrapTool(clangppTool,"ClangWrapper",sv); + wrapTool(arTool,"ArWrapper",sv); + wrapTool(ldTool,"LdWrapper",sv); + wrapTool(lnTool,"LnWrapper",sv); + wrapTool(llvmarTool,"ArWrapper",sv); + wrapTool(llvmldTool,"LdWrapper",sv); + wrapTool("cp","CopyMoveWrapper",sv); + wrapTool("mv","CopyMoveWrapper",sv); + + // creating rm wrapper script + std::ofstream rm_wrapper((wrapperWorkDirBin / "rm").string().c_str()); + if (rm_wrapper) { + rm_wrapper << "#!/bin/sh\n/bin/rm -rf \"$@\"" << endl; + rm_wrapper.close(); + boost::filesystem::permissions(wrapperWorkDirBin / "rm", boost::filesystem::add_perms | boost::filesystem::owner_exe | boost::filesystem::group_exe | boost::filesystem::others_exe ); + } else { + logstream << CMSG_CAN_NOT_CREATE_RM_WRAPPER_ERROR << endl; + result.setError(); + } + + sv.push_back("-setWrapperRunFirst"); + sv.push_back("cp"); + sv.push_back("1"); + + sv.push_back("-setWrapperRunFirst"); + sv.push_back("mv"); + sv.push_back("1"); + + sv.push_back("-setWrappedExtraParamToBegin"); + sv.push_back("cp"); + sv.push_back("-R"); + + if (!props.externalHardFilter.empty()) { + sv.push_back("-setWrappedParamlistFilter"); + sv.push_back(clangTool); + sv.push_back(props.externalHardFilter.string()); + + sv.push_back("-setWrappedParamlistFilter"); + sv.push_back(clangppTool); + sv.push_back(props.externalHardFilter.string()); + + sv.push_back("-setWrappedParamlistFilter"); + sv.push_back(arTool); + sv.push_back(props.externalHardFilter.string()); + + sv.push_back("-setWrappedParamlistFilter"); + sv.push_back(ldTool); + sv.push_back(props.externalHardFilter.string()); + + sv.push_back("-setWrappedParamlistFilter"); + sv.push_back(llvmarTool); + sv.push_back(props.externalHardFilter.string()); + + sv.push_back("-setWrappedParamlistFilter"); + sv.push_back(llvmldTool); + sv.push_back(props.externalHardFilter.string()); + + } + } + else + { + throw Exception(COLUMBUS_LOCATION, "FAIL no wrapper config for this target."); + } + + sv.push_back("-workingdir"); + sv.push_back(wrapperWorkDir.string()); + sv.push_back(wrapperEnvironmentConfigPath.string()); + + checkedExec(props.wrapperBinDir / "WrapperEnvironmentConfig", sv, logger); + + SafeEnvironmentModifier config_env(OSA_WRAPPER_CONFIG_FILE_ENV_VAR, wrapperEnvironmentConfigPath, logger); + + // ---------------------------------------------------------------------------------------------------------------------- + // --------------------------------------------------- AnalyzerWrapperConfig -------------------------------------------- + // ---------------------------------------------------------------------------------------------------------------------- + + sv.clear() ; + sv.push_back("-needToRun"); + sv.push_back("compiler"); + sv.push_back("1"); + + sv.push_back("-toolMessageLevel"); + sv.push_back("compiler"); + addMessageLevelNumber(sv, 4, 3); + + sv.push_back("-messageLevel"); + addMessageLevelNumber(sv, 4, 3); + + sv.push_back("-needToRun"); + sv.push_back("linker"); + sv.push_back("1"); + + sv.push_back("-toolMessageLevel"); + sv.push_back("linker"); + addMessageLevelNumber(sv, 4, 3); + + sv.push_back("-needToRun"); + sv.push_back("archive"); + sv.push_back("1"); + + sv.push_back("-toolMessageLevel"); + sv.push_back("archive"); + addMessageLevelNumber(sv, 4, 3); + + if (!props.externalSoftFilter.empty()) { + sv.push_back("-linkerFilterFile"); + sv.push_back(props.externalSoftFilter.string()); + } + + if (props.runCppcheck) { + sv.push_back("-runCppcheck"); + sv.push_back("1"); + } + + if (props.wrapperMode == WM_CL) + { + if (props.noDelayedTemplateParsing) { + sv.push_back("-noDelayedTemplateParsing"); + sv.push_back("1"); + } + } + + sv.push_back("-outputDir"); + sv.push_back(props.analysisOutputDir); + + checkedExec(wrapperWorkDirBin / "AnalyzerWrapperConfig", sv, logger); + + // ---------------------------------------------------------------------------------------------------------------------- + + string oldPath; + const char* pathValue = getenv("PATH"); + if (pathValue != NULL) + oldPath = pathValue; + + SafeEnvironmentModifier path_env("PATH", ((wrapperWorkDir / "bin").string() + PATH_SEPARATOR + oldPath).c_str(), logger, false); + + sv.clear(); + checkedExec(props.buildScript, sv, logger); + + if (exists(wrapperWorkDirLog / "Error.log")) { + logstream << CMSG_WRAPPER_ERROR << endl; + result.setError(CMSG_WRAPPER_ERROR); + } + boost::system::error_code ec; + auto componentListSize = file_size(wrapperWorkDirLog / "component.list", ec); + if (ec) + componentListSize = 0; + + auto aastListSize = file_size(wrapperWorkDirLog / "aast.list", ec); + if (ec) + aastListSize = 0; + + if ((componentListSize == 0) && (aastListSize == 0)) + { + logstream << CMSG_NO_OUTPUT_ERROR << endl; + result.setCriticalError(CMSG_NO_OUTPUT_ERROR); + } + } HANDLE_TASK_EXCEPTIONS + + return result; +} + +WrapperTask::WrapperTask(const Properties& properties) : Task(properties) +{ + addDependsOn(CleanResultsTask::name); +} + +void WrapperTask::wrapTool(const string& wrappedTool, const string& wrapperTool, vector& sv ) const +{ + sv.push_back("-wraptools"); + sv.push_back(wrappedTool); + sv.push_back(wrapperTool); + copy_file(props.wrapperBinDir/wrapperTool, props.columbusWrapperTmpDir/"bin"/wrapperTool, copy_option::overwrite_if_exists); + copy_file(props.wrapperBinDir/("exewrapper" BINARYEXT), props.columbusWrapperTmpDir/"bin"/wrappedTool); +} + + + +TASK_NAME_DEF(Can2limTask); + +Task::ExecutionResult Can2limTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + + try { + + vector sv; + addMessageLevel(sv); + + sv.push_back("-ilist:" + (props.columbusWrapperTmpDir / "log" / "component.list").string()); + sv.push_back("-out:" + (props.asgDir / (props.projectName + ".lim")).string()); + + if (props.maxCan2LimThreads > 0) + sv.push_back("-maxThreads:" + to_string(props.maxCan2LimThreads)); + + if (!props.externalSoftFilter.empty()) + sv.push_back("-fltp:" + props.externalSoftFilter.string()); + + checkedExec(props.toolsDir / "CAN2Lim", sv, logger); + + } HANDLE_TASK_EXCEPTIONS + + return result; +} + +Can2limTask::Can2limTask(const Properties& properties) : Task(properties) +{ + addDependsOn(LinkStaticLibsTask::name); + addDependsOn(StaticLibHandlerTask::name); + addDependsOn(WrapperTask::name); +} + +TASK_NAME_DEF(ProfileTask); + +Task::ExecutionResult ProfileTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + try { + + // original rul files + path CppcheckRulFileOrig = props.toolsDir / "Cppcheck.rul"; + path ClangTidyRulFileOrig = props.toolsDir / "ClangTidy.rul"; + + // temp rul files + path CppcheckRulFile = props.tempDir / "Cppcheck.rul"; + path ClangTidyRulFile = props.tempDir / "ClangTidy.rul"; + + path ClangTidyConfigFile = props.tempDir / "ClangTidy.conf"; + + // copy original rul files into temp + if (exists(CppcheckRulFileOrig)) + copy_file(CppcheckRulFileOrig, CppcheckRulFile); + if (exists(ClangTidyRulFileOrig)) + copy_file(ClangTidyRulFileOrig, ClangTidyRulFile); + + // data + ProfileHandler profile; + map rulHandlers; // for rul files + map runTool; // running tools + + // load profile + if(!props.profileXML.empty()) + profile.parseXML(props.profileXML.string()); + + + // load rul files + rul::RulHandler cppcheckrh(CppcheckRulFile.string(), "Default", "eng"); + rul::RulHandler ctrh(ClangTidyRulFile.string(), "Default", "eng"); + + rulHandlers.insert(make_pair("CPPCHECK", &cppcheckrh)); + rulHandlers.insert(make_pair("CT", &ctrh)); + + // set running tools + runTool.insert(make_pair("CPPCHECK", props.runCppcheck)); + runTool.insert(make_pair("CT", props.runClangTidy)); + + //process rules csv + profileProcessRulesCSV(profile, rulHandlers, runTool, props.rulesCSV.string()); + + + path MetricHunterThresholdsFileOrig = props.toolsDir / "MetricHunter.threshold"; + path MetricHunterThresholdsFile = props.tempDir / "MetricHunter.threshold"; + + //process thresholds + profileProcessToolThresholds(profile, "MetricHunter", MetricHunterThresholdsFileOrig.string(), MetricHunterThresholdsFile.string()); + + //generate clang-tidy config file + generateClangTidyConfigFile(ctrh,ClangTidyConfigFile.string()); + + + + //process udm metrics + bool UDM_result = profileProcessUDM(profile, (props.tempDir / "UDM.rul").string(), "cpp"); + if (!props.runUDMExplicit) { + // if runUDM wasn't explicitly set, we decide by the presence of UDM metrics in the profile + props.runUDM = UDM_result; + } + else if (props.runUDMExplicit && props.runUDM && !UDM_result) { + // if, however, runUDM was explicitly set to true, but there are no valid UDM metrics, we abort + throw Exception(COLUMBUS_LOCATION, "UDM explicitly set to run without corresponding setup in the profile XML"); + } + + //process lim2patterns parameters + if (props.runLIM2Patterns) { + map parameters; + if (profileProcessLIM2Patterns(profile, "LIM2Patterns", parameters)) { + if (parameters.find("whitelist") != parameters.end()) { + props.whitelist = parameters["whitelist"]; + } + if (parameters.find("blacklist") != parameters.end()) { + props.blacklist = parameters["blacklist"]; + } + if (parameters.find("pattern_directories") != parameters.end()) { + props.patternFile = parameters["pattern_directories"]; + } + } + } + + } HANDLE_TASK_EXCEPTIONS + return result; +} + +ProfileTask::ProfileTask(const Properties& properties) : Task(properties) +{ + addDependsOn(Can2limTask::name); +} + +TASK_NAME_DEF(Cppcheck2GraphTask); + +Task::ExecutionResult Cppcheck2GraphTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + + try { + vector sv; + addMessageLevel(sv); + + sv.push_back("-graph:" + (props.graphDir / (props.projectName + "-cppcheck.graph")).string()); + sv.push_back("-rul:" + (props.tempDir / "Cppcheck.rul").string()); + sv.push_back("-exportrul"); + sv.push_back("-lim:" + (props.asgDir / (props.projectName + ".lim")).string()); + sv.push_back("-inputlist:" + (props.columbusWrapperTmpDir / "log" / "ast.list").string()); + sv.push_back("-out:" + (props.projectTimedResultDir / (props.projectName + "-Cppcheck.txt")).string()); + + checkedExec(props.toolsDir / "Cppcheck2Graph", sv, logger, false); + + } HANDLE_TASK_EXCEPTIONS + + return result; +} + +Cppcheck2GraphTask::Cppcheck2GraphTask(const Properties& properties) : Task(properties) +{ + addDependsOn(LinkStaticLibsTask::name); + addDependsOn(WrapperTask::name); + addDependsOn(Can2limTask::name); + addDependsOn(ProfileTask::name); +} + +TASK_NAME_DEF(Lim2metricsTask); + +Task::ExecutionResult Lim2metricsTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + + try { + vector sv; + addMessageLevel(sv); + + sv.push_back("-graph:" + (props.graphDir / (props.projectName + "-metrics.graph")).string()); + sv.push_back("-rul:" + (props.toolsDir / "MET.rul").string()); + sv.push_back("-rulconfig:cpp"); + sv.push_back("-exportrul"); + sv.push_back((props.asgDir / (props.projectName + ".lim")).string()); + + checkedExec(props.toolsDir / "LIM2Metrics", sv, logger, false); + + } HANDLE_TASK_EXCEPTIONS + + return result; +} + +Lim2metricsTask::Lim2metricsTask(const Properties& properties) : Task(properties) +{ + addDependsOn(LinkStaticLibsTask::name); + addDependsOn(WrapperTask::name); + addDependsOn(Can2limTask::name); +} + +TASK_NAME_DEF(DcfTask); + +Task::ExecutionResult DcfTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + + try { + + vector sv; + addMessageLevel(sv); + + sv.push_back("-inputlist:" + (props.columbusWrapperTmpDir / "log" / "component.list").string()); + sv.push_back("-lim:" + (props.asgDir / (props.projectName + ".lim")).string()); + sv.push_back("-graph:" + (props.graphDir / (props.projectName + "-DCF.graph")).string()); + sv.push_back("-metrics"); + sv.push_back("-multipleasgroot"); + sv.push_back("-onlyfunctionclone"); + sv.push_back("-out:" + (props.projectTimedResultDir / (props.projectName + "-clones.txt")).string()); + sv.push_back("-patternfilterlog:" + (props.logDir / "clone-filter.log").string()); + sv.push_back("-patternfilter"); + sv.push_back("30"); + sv.push_back("100"); + sv.push_back("-rul:" + (props.toolsDir / "DCF.rul").string()); + sv.push_back("-rulconfig:cpp"); + sv.push_back("-exportrul"); + + if (props.cloneMinLines != -1) + sv.push_back("-minlines:" + common::toString(props.cloneMinLines)); + if (props.cloneGenealogy){ + sv.push_back("-genealogy:" + (props.projectResultDir / (props.projectName + ".gsi")).string()); + } + + if (!props.externalSoftFilter.empty()) + sv.push_back("-fltp:" + props.externalSoftFilter.string()); + + checkedExec(props.toolsDir / "DuplicatedCodeFinder", sv, logger, false); + + } HANDLE_TASK_EXCEPTIONS + + return result; +} + +DcfTask::DcfTask(const Properties& properties) : Task(properties) +{ + addDependsOn(LinkStaticLibsTask::name); + addDependsOn(StaticLibHandlerTask::name); + addDependsOn(WrapperTask::name); + addDependsOn(Can2limTask::name); +} + +TASK_NAME_DEF(ClangTidyTask); + +void ClangTidyTask::Worker::operator()() +{ + std::fstream logstream(logDir, ios_base::binary | ios_base::app); + while (true) + { + bool result = false; + vector args; + { + // Take the next set of arguments to invoke clang-tidy with + boost::lock_guard lock(m); + if (clangtidy_args.empty()) + break; + args = clangtidy_args.front(); + clangtidy_args.pop(); + } + // Invoke clang-tidy with the arguments + result = exec(program, args, logstream); + + { + boost::lock_guard lock(m); + + if (result) + *failure = true; + } + + if(threadsLeft.load() > 0) + threadsLeft--; + } + cv.notify_all(); +} + +Task::ExecutionResult ClangTidyTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + + try { + path wrapperWorkDir = props.columbusWrapperTmpDir; + path wrapperWorkDirLog = wrapperWorkDir / "log"; + const string ClangTidyConfigFile = (props.tempDir / "ClangTidy.conf").string(); + const boost::filesystem::path& clangTidyPath = props.wrapperToolsDir / "clang-tidy"; + + list astList; + + if (loadStringListFromFile((wrapperWorkDirLog / "ast.list").string(), astList)) + { + astList.sort(); + astList.unique(); + + // Start running clang-tidy on multiple threads + queue> clangtidy_args; // Holds the arguements for each seperate run of the clang-metrics + boost::condition_variable cv; // Used to notify the main thread when a thread has finished + boost::mutex m; + std::atomic threadsLeft(astList.size()); // Used my the main thread to check if all other threads have finished + vector results(props.maxThreads, 0); // For each thread holds if any of it's clang-tidy executions failed + + // Setup the arguements + for (const auto& fileName : astList) + { + string clangTidyOutputFile = fileName + ".ct.err"; + pathDeleteFile(clangTidyOutputFile); + + vector args; + args.push_back(fileName); + args.push_back("-config-file=" + ClangTidyConfigFile); + args.push_back("-xml=" + clangTidyOutputFile); + args.push_back("--"); + clangtidy_args.push(args); + } + + + + // Start the threads which will run clang-tidy with the given arguements, the current thread is already running on the threadPool so (maxThreads - 1) threads can be started + for (int i = 1; i < props.maxThreads; i++) + { + if(!clangtidy_args.empty()) + { + string logDir = (properties.logDir / (getName() + "-T" + to_string(i) + ".log")).string(); + int* taskResult = &results[i]; + threadPool.add(columbus::thread::ThreadPool::PtrTask(new Worker(clangTidyPath, clangtidy_args, logDir, m, cv, threadsLeft, taskResult))); + } + } + + { + // Start a worker on this thread too + string logDir = (properties.logDir / (getName() + "-T0.log")).string(); + int* taskResult = &results[0]; + Worker worker(clangTidyPath, clangtidy_args, logDir, m, cv, threadsLeft, taskResult); + worker(); + } + + // Wait for all the threads to finish + boost::unique_lock lock(m); + cv.wait(lock, [&threadsLeft]() { return threadsLeft.load() == 0; }); + + // Delete any empty log files + for (int i = 0; i < props.maxThreads; i++) + { + string logDir = (properties.logDir / (getName() + "-T" + to_string(i) + ".log")).string(); + if (std::ifstream(logDir)) + if (file_size(logDir) == 0) + std::remove(logDir.c_str()); + } + + bool failure = false; + string errorMsg = "ERROR: Execution failure! \nCheck logs:\n"; + for (int i = 0; i < props.maxThreads; i++) + { + if (results.at(i) == 1) + { + failure = true; + errorMsg += (properties.logDir / (getName() + "-T" + to_string(i) + ".log")).string() + "\n"; + } + } + + logger.errorIfFail(!failure, errorMsg.c_str()); + + vector tidy2graphArgs; + + tidy2graphArgs.push_back("-graph:" + (props.graphDir / (props.projectName + "-clangtidy.graph")).string()); + tidy2graphArgs.push_back("-rul:" + (props.tempDir / "ClangTidy.rul").string()); + tidy2graphArgs.push_back("-exportrul"); + tidy2graphArgs.push_back("-lim:" + (props.asgDir / (props.projectName + ".lim")).string()); + tidy2graphArgs.push_back("-inputlist:" + (props.columbusWrapperTmpDir / "log" / "ast.list").string()); + tidy2graphArgs.push_back("-out:" + (props.projectTimedResultDir / (props.projectName + "-ClangTidy.txt")).string()); + + checkedExec(props.toolsDir / "ClangTidy2Graph", tidy2graphArgs, logger, false); + } + } HANDLE_TASK_EXCEPTIONS + + return result; +} + +ClangTidyTask::ClangTidyTask(const Properties& properties, columbus::thread::ThreadPool& threadPool) : Task(properties), threadPool(threadPool) +{ + addDependsOn(Can2limTask::name); + addDependsOn(ProfileTask::name); +} + +TASK_NAME_DEF(Lim2umlTask); + +Task::ExecutionResult Lim2umlTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + + try { + + } HANDLE_TASK_EXCEPTIONS + return result; +} + +Lim2umlTask::Lim2umlTask(const Properties& properties) : Task(properties) +{ + addDependsOn(LinkStaticLibsTask::name); + addDependsOn(WrapperTask::name); + addDependsOn(Can2limTask::name); +} + +TASK_NAME_DEF(GraphMergeTask); + +Task::ExecutionResult GraphMergeTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + try { + vector sv; + addMessageLevel(sv); + + directory_iterator end; + + for (directory_iterator fileIterator(props.graphDir); fileIterator != end; ++fileIterator) { + sv.push_back(fileIterator->path().string()); + } + sort(sv.begin(), sv.end()); + sv.push_back("-out:" + (props.projectTimedResultDir / (props.projectName + ".graph")).string()); + sv.push_back("-summary"); + + checkedExec(props.toolsDir / "GraphMerge", sv, logger); + + } HANDLE_TASK_EXCEPTIONS + + return result; +} + +GraphMergeTask::GraphMergeTask(const Properties& properties) : Task(properties) +{ + addDependsOn(LinkStaticLibsTask::name); + addDependsOn(WrapperTask::name); + addDependsOn(Cppcheck2GraphTask::name); + addDependsOn(Lim2metricsTask::name); + addDependsOn(DcfTask::name); + addDependsOn(Sonar2GraphTask::name); + addDependsOn(ClangTidyTask::name); +} + + +TASK_NAME_DEF(GraphDumpTask); + +Task::ExecutionResult GraphDumpTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + try + { + { + vector sv; + addMessageLevel(sv); + + sv.push_back((props.projectTimedResultDir / (props.projectName + ".graph")).string()); + sv.push_back("-csv"); + sv.push_back("-xml"); + sv.push_back("-csvseparator:" + string(1, props.csvSeparator)); + sv.push_back("-csvdecimalmark:" + string(1, props.csvDecimalmark)); + sv.push_back("-sarif"); + sv.push_back("-sarifseverity:" + props.sarifSeverityLevel); + + checkedExec(props.toolsDir / "GraphDump", sv, logger); + } + + { + vector sv; + addMessageLevel(sv); + + sv.push_back((props.projectTimedResultDir / (props.projectName + "-summary.graph")).string()); + sv.push_back("-xml"); + sv.push_back("-json"); + + checkedExec(props.toolsDir / "GraphDump", sv, logger); + } + + } HANDLE_TASK_EXCEPTIONS + + return result; +} + +GraphDumpTask::GraphDumpTask(const Properties& properties) : Task(properties) +{ + addDependsOn(GraphMergeTask::name); + addDependsOn(MetricHunterTask::name); + addDependsOn(UserDefinedMetricsTask::name); + addDependsOn(LIM2PatternsTask::name); +} + + +TASK_NAME_DEF(CleanResultsTask); + +Task::ExecutionResult CleanResultsTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + try { + set directoryList; + directory_iterator end; + directory_iterator begin(props.projectResultDir); + for( directory_iterator iter = begin; iter != end ; ++iter ) { + if (is_directory(iter->path())) { + static const regex dateFormatRegexpr("\\d{4}(-\\d{2}){5}"); + if (regex_match(iter->path().filename().string(), dateFormatRegexpr)) + directoryList.insert(*iter); + } + } + + set::const_iterator dirIt = directoryList.begin(); + int toBeDeletedCounter = (int)directoryList.size() - props.cleanResults - 1; + for (int dirCounter = 0; dirCounter < toBeDeletedCounter; ++dirCounter) { + logstream << "Removing directory:" << dirIt->string() << "\n"; + remove_all(*dirIt); + ++dirIt; + } + + if (props.cleanResults == 0) { + path genealogyFile = props.projectResultDir / (props.projectName + ".gsi"); + logstream << "Removing genealogy file:" << genealogyFile.string() << "\n"; + logger.warningIfFail(remove(genealogyFile), "Failed to remove the genealogy file:%s\n", genealogyFile.string().c_str()); + + path lastMergedGraph = props.projectResultDir / (props.projectName + ".graph"); + logstream << "Removing the graph file:" << lastMergedGraph.string() << "\n"; + logger.warningIfFail(remove(lastMergedGraph), "Failed to remove the graph file:%s\n", lastMergedGraph.string().c_str()); + } + + } HANDLE_TASK_EXCEPTIONS + + return result; + +} + +CleanResultsTask::CleanResultsTask(const Properties& properties) : Task(properties) +{ + // there is no dependency +} + +TASK_NAME_DEF(MetricHunterTask); + +Task::ExecutionResult MetricHunterTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + + try { + + string graphFile = (props.projectTimedResultDir / (props.projectName + ".graph")).string(); + + vector sv; + addMessageLevel(sv); + + sv.push_back("-graph:" + graphFile); + sv.push_back("-out:" + (props.projectTimedResultDir / (props.projectName + "-MetricHunter.txt")).string()); + sv.push_back("-thresholds:" + (props.tempDir / "MetricHunter.threshold").string()); + + sv.push_back("-exportrul"); + sv.push_back(graphFile); + + + checkedExec(props.toolsDir / "MetricHunter", sv, logger, false); + + } HANDLE_TASK_EXCEPTIONS + + return result; +} + +MetricHunterTask::MetricHunterTask(const Properties& properties) : Task(properties) +{ + addDependsOn(GraphMergeTask::name); +} + +TASK_NAME_DEF(LinkStaticLibsTask); + +Task::ExecutionResult LinkStaticLibsTask::execute() { + ExecutionResult result; + ExecutionLogger logger(this, result); + + try { + + path wrapperWorkDir = props.columbusWrapperTmpDir; + path wrapperWorkDirBin = wrapperWorkDir / "bin"; + path wrapperWorkDirLog = wrapperWorkDir / "log"; + + list aastList; + if (loadStringListFromFile((wrapperWorkDirLog / "aast.list").string(), aastList)) { + aastList.sort(); + aastList.unique(); + for (const auto& filename : aastList) + { + if (filename.length() > 5) { + string outputname = filename.substr(0, filename.length() - 4) + "component"; + std::ofstream componentFile(outputname.c_str(), ios::trunc); + if (componentFile) + { + const string componentDirectoryName = filename + ".content"; + TemporalArhiveExtractor tae(filename, componentDirectoryName, true); + for (const auto& astFilename : tae.getFileList()) + componentFile << astFilename << endl; + archives.push_back(std::move(tae)); + componentFile.close(); + } + + std::ofstream componentlist((wrapperWorkDirLog / "component.list").string().c_str(), ios::app); + if (componentlist) { + componentlist << outputname << endl; + componentlist.close(); + } else { + logstream << CMSG_CANNOT_OPEN_LCSI_FOR_WRITING << endl; + } + + } else { + logstream << CMSG_TOO_SHORT_ACSI_NAME << "('" << filename << "')" << endl; + } + } + } + } HANDLE_TASK_EXCEPTIONS + + return result; +} + +LinkStaticLibsTask::LinkStaticLibsTask(const Properties& properties) : Task(properties) +{ + addDependsOn(WrapperTask::name); +} + +namespace { + + void generateClangTidyConfigFile(rul::RulHandler& rulHandler, const string& outputFileName) + { + vector disabledRules; + vector groupIDs; + vector groupMembers; + + //Get group ids. + rulHandler.getGroupIdList(groupIDs); + + for(const auto& groupID : groupIDs) + { + rulHandler.getGroupMembers(groupID, groupMembers); + + if (!rulHandler.getIsEnabled(groupID)) + { + disabledRules.push_back(groupID + "*"); + } + else + { + for (const auto& rule : groupMembers) + { + if (!rulHandler.getIsEnabled(rule)) + { + disabledRules.push_back(rulHandler.getOriginalIdByRuleId(rule)); + } + } + } + groupMembers.clear(); + } + + //All checks are enabled by default + string checks = "*"; + + if (disabledRules.size() > 0) + { + //Concatenate disabled checks + std::ostringstream buf; + copy(disabledRules.begin(), disabledRules.end(), ostream_iterator(buf, ",-")); + + string strDisabledRules("-" + buf.str()); + strDisabledRules = strDisabledRules.substr(0, strDisabledRules.size() - 2); + checks = checks + ',' + strDisabledRules; + } + + std::ofstream out(outputFileName, std::ofstream::out | std::ofstream::app); + if (!out) + { + const char *cstr = outputFileName.c_str(); + WriteMsg::write(CMSG_FAILED_TO_OPEN_FILE, cstr); + } + else + { + out << "Checks: '" << checks << "'" << endl; + out << "WarningsAsErrors: ''" << endl; + out << "HeaderFilterRegex: ''" << endl; + out << "AnalyzeTemporaryDtors: false" << endl; + out.close(); + } + } +} + +TASK_NAME_DEF(UserDefinedMetricsTask); + +Task::ExecutionResult UserDefinedMetricsTask::execute() +{ + ExecutionResult result; + if (!props.runUDM) { + inactives.push_back("UserDefinedMetrics"); + return result; + } + + ExecutionLogger logger(this, result); + + try { + vector sv; + sv.push_back((props.projectTimedResultDir / (props.projectName + ".graph")).string()); + sv.push_back("-rul:" + (props.tempDir / "UDM.rul").string()); + sv.push_back("-rulconfig:cpp"); + sv.push_back("-graph:" + (props.projectTimedResultDir / (props.projectName + ".graph")).string()); + + checkedExec(props.toolsDir / "UserDefinedMetrics", sv, logger); + + } HANDLE_TASK_EXCEPTIONS + + return result; +} + +UserDefinedMetricsTask::UserDefinedMetricsTask(list& inactives, const Properties& properties) : Task(properties), inactives(inactives) +{ + addDependsOn(GraphMergeTask::name); + addDependsOn(MetricHunterTask::name); +} + +TASK_NAME_DEF(StaticLibHandlerTask); + +Task::ExecutionResult StaticLibHandlerTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + + try + { + path wrapperWorkDir = props.columbusWrapperTmpDir; + path wrapperWorkDirBin = wrapperWorkDir / "bin"; + path wrapperWorkDirLog = wrapperWorkDir / "log"; + + list aastList; + if (loadStringListFromFile((wrapperWorkDirLog / "aast.list").string(), aastList)) + { + aastList.sort(); + aastList.unique(); + for (const auto& filename : aastList) + { + if (filename.length() > 5) { + string outputname = filename.substr(0, filename.length() - 4) + "component"; + std::ofstream componentFile(outputname.c_str(), ios::trunc); + if (componentFile) + { + const string componentDirectoryName = filename + ".content"; + TemporalArhiveExtractor tae(filename, componentDirectoryName, true); + for (const auto& astFilename : tae.getFileList()) + componentFile << astFilename << "\n"; + archives.push_back(std::move(tae)); + componentFile.close(); + } + } else { + logstream << CMSG_TOO_SHORT_ACSI_NAME << "('" << filename << "')" << endl; + } + } + } + + list componentList; + if (loadStringListFromFile((wrapperWorkDirLog / "component.list").string(), componentList)) + { + for (const auto& componentFilename : componentList) + { + list astFilesOfTheComponent; + loadStringListFromFile(componentFilename, astFilesOfTheComponent); + // this looks weird + for (auto astFilenameIerator = astFilesOfTheComponent.begin(); astFilenameIerator != astFilesOfTheComponent.end(); ++astFilenameIerator) + { + if (pathFindExtension(*astFilenameIerator) == "aast") + { + list astFilesOfTheStaticLib; + const string componentFilenameOfTheStaticLib = pathRemoveExtension(*astFilenameIerator) + ".component"; + loadStringListFromFile(componentFilenameOfTheStaticLib, astFilesOfTheStaticLib); + for (const auto& extractedAstFilename : astFilesOfTheStaticLib) + astFilesOfTheComponent.insert(astFilenameIerator, extractedAstFilename); + + astFilenameIerator = astFilesOfTheComponent.erase(astFilenameIerator); + if (astFilenameIerator == astFilesOfTheComponent.end()) + break; + } + } + + std::ofstream componentFile(componentFilename.c_str(), ios::trunc); + if (componentFile) + { + for (const auto& astFilename : astFilesOfTheComponent) + componentFile << astFilename << "\n"; + componentFile.close(); + } + } + } + + } HANDLE_TASK_EXCEPTIONS + + return result; +} + +StaticLibHandlerTask::StaticLibHandlerTask(const Properties& properties) : Task(properties) +{ + addDependsOn(WrapperTask::name); +} + +SONAR2GRAPH_TASK(cpp) + +Sonar2GraphTask::Sonar2GraphTask(const Properties& properties) : Task(properties) +{ + addDependsOn(Can2limTask::name); +} + +TASK_NAME_DEF(LIM2PatternsTask); + +Task::ExecutionResult LIM2PatternsTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + try { + vector sv; + + sv.push_back("-graph:" + (props.projectTimedResultDir / (props.projectName + ".graph")).string()); + sv.push_back("-lim:" + (props.asgDir / (props.projectName + ".lim")).string()); + sv.push_back("-pattern:" + props.patternFile + (!props.patternFile.empty() ? "," : "") + (props.toolsDir / "Patterns" / "AntiPatterns").string()); + sv.push_back("-metrics:" + (props.toolsDir / "MET.rul").string()); + sv.push_back("-out:" + (props.projectTimedResultDir / (props.projectName + ".txt")).string()); + + if (!props.whitelist.empty()) { + sv.push_back("-whitelist:" + props.whitelist); + } + if (!props.blacklist.empty()) { + sv.push_back("-blacklist:" + props.blacklist); + } + + checkedExec(props.toolsDir / "LIM2Patterns", sv, logger); + + + } HANDLE_TASK_EXCEPTIONS + + return result; +} + +LIM2PatternsTask::LIM2PatternsTask(const Properties& properties) : Task(properties) { + addDependsOn(GraphMergeTask::name); + addDependsOn(MetricHunterTask::name); + addDependsOn(UserDefinedMetricsTask::name); +} diff --git a/cl/OpenStaticAnalyzerCPP/src/main.cpp b/cl/OpenStaticAnalyzerCPP/src/main.cpp new file mode 100644 index 0000000..4f60a0b --- /dev/null +++ b/cl/OpenStaticAnalyzerCPP/src/main.cpp @@ -0,0 +1,606 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "../inc/messages.h" +#include "../inc/Properties.h" +#include "../inc/Task.h" + +#define PROGRAM_NAME "OpenStaticAnalyzerCPP" +#define EXECUTABLE_NAME "OpenStaticAnalyzerCPP" + +#include "MainCommon.h" + +using namespace std; +using namespace common; +using namespace boost::filesystem; +using namespace columbus::controller; + +Properties props; + +static void ppFile(char *str) { + +} + +bool ppResultsDir(const common::Option *o, char *argv[]) { + props.resultsDir = argv[0]; + return true; +} + +bool ppProjectName(const common::Option *o, char *argv[]) { + props.projectName = argv[0]; + return true; +} + +bool ppBuildScript(const common::Option *o, char *argv[]) { + props.buildScript = argv[0]; + return true; +} + +bool ppExternalHardFilter(const common::Option *o, char *argv[]) { + props.externalHardFilter = argv[0]; + return true; +} + +bool ppExternalSoftFilter(const common::Option *o, char *argv[]) { + props.externalSoftFilter = argv[0]; + return true; +} + +bool ppPrefix(const common::Option *o, char *argv[]) { + props.prefix = argv[0]; + return true; +} + +bool ppPostfix(const common::Option *o, char *argv[]) { + props.postfix = argv[0]; + return true; +} + +bool ppMaxThreads(const common::Option *o, char *argv[]) { + props.maxThreads = common::str2int(argv[0]); + return true; +} + +bool ppCan2LimMaxThreads(const common::Option* o, char* argv[]) { + props.maxCan2LimThreads = common::str2int(argv[0]); + return true; +} + +bool ppCurrentDate(const common::Option *o, char *argv[]) { + props.currentDate = argv[0]; + return true; +} + +bool ppCleanResults(const common::Option *o, char *argv[]) { + props.cleanResults = common::str2int(argv[0]); + return true; +} + +bool ppCppcheck(const common::Option *o, char *argv[]) { + if(strcmp(argv[0], "true") == 0) + props.runCppcheck = true; + else + props.runCppcheck = false; + return true; +} + +bool ppClangTidy(const common::Option *o, char *argv[]) { + if(strcmp(argv[0], "true") == 0) + props.runClangTidy = true; + else + props.runClangTidy = false; + return true; +} + +bool ppCleanProject(const common::Option *o, char *argv[]) { + props.cleanProject = true; + props.projectBaseDir = argv[0]; + return true; +} + +bool ppCloneGenealogy (const common::Option *o, char *argv[]) { + if(strcmp(argv[0], "true") == 0) + props.cloneGenealogy = true; + else + props.cloneGenealogy = false; + return true; +} + +bool ppCsvDecimalMark (const common::Option *o, char *argv[]) { + if (argv[0][0] != 0) + props.csvDecimalmark = argv[0][0]; + return true; +} + +bool ppCsvSeparator (const common::Option *o, char *argv[]) { + if (strcmp(argv[0], "\\t") == 0) + props.csvSeparator = '\t'; + else if (argv[0] != 0) + props.csvSeparator = argv[0][0]; + + return true; +} + +bool ppCloneMinLines(const common::Option *o, char *argv[]) { + props.cloneMinLines = common::str2int(argv[0]); + return true; +} + +bool ppRunMetricHunter(const common::Option *o, char *argv[]) { + if(strcmp(argv[0], "true") == 0) + props.runMetricHunter = true; + else + props.runMetricHunter = false; + return true; +} + +bool ppRunDCF(const common::Option *o, char *argv[]) { + if(strcmp(argv[0], "true") == 0) + props.runDCF = true; + else + props.runDCF = false; + return true; +} + +bool ppRunMET(const common::Option *o, char *argv[]) { + if(strcmp(argv[0], "true") == 0) + props.runLimMetrics = true; + else + props.runLimMetrics = false; + return true; +} + +bool ppRunUDM(const common::Option *o, char *argv[]) { + props.runUDMExplicit = true; + if (strcmp(argv[0], "true") == 0) + props.runUDM = true; + else + props.runUDM = false; + return true; +} + +bool ppProfileXML(const common::Option *o, char *argv[]) { + props.profileXML = argv[0]; + return true; +} + +bool ppRulesCSV(const common::Option *o, char *argv[]) { + props.rulesCSV = argv[0]; + return true; +} + + +bool ppVerbose(const common::Option *o, char *argv[]) { + WriteMsg::setMessageLevel(WriteMsg::mlDebug); + props.verbose = true; + return true; +} + +bool ppFaultTolerant(const common::Option *o, char *argv[]) { + if(strcmp(argv[0], "true") == 0) + props.faultTolerantMode = true; + else + props.faultTolerantMode = false; + + return true; +} + +bool ppNoDelayedTemplateParsing(const common::Option *o, char *argv[]) { + props.noDelayedTemplateParsing = true; + return true; +} + +CL_PPSARIFSEVERITY + +bool ppRunSonar2Graph(const common::Option *o, char *argv[]) { + props.runSonar2Graph = argv[0]; + return true; +} + +bool ppHost(const common::Option *o, char *argv[]) { + props.host = argv[0]; + return true; +} + +bool ppPort(const common::Option *o, char *argv[]) { + props.port = argv[0]; + return true; +} + +bool ppProjectKey(const common::Option *o, char *argv[]) { + props.projectKey = argv[0]; + return true; +} + +bool ppProjectPrefix(const common::Option *o, char *argv[]) { + props.projectPrefix = argv[0]; + return true; +} + +bool ppJsonPath(const common::Option *o, char *argv[]) { + props.jsonPath = argv[0]; + return true; +} + +bool ppSqUsername(const common::Option *o, char *argv[]) { + props.sqUsername = argv[0]; + return true; +} + +bool ppSqPassword(const common::Option *o, char *argv[]) { + props.sqPassword = argv[0]; + return true; +} + +bool ppLanguageKey(const common::Option *o, char *argv[]) { + props.languageKey = argv[0]; + return true; +} + +bool ppStrict(const common::Option *o, char *argv[]) { + if(strcmp(argv[0], "true") == 0) + props.strict = true; + else + props.strict = false; + return true; +} + +// LIM2Patterns start:: +bool ppRunLIM2Patterns(const common::Option *o, char *argv[]) { + if (strcmp(argv[0], "true") == 0) + props.runLIM2Patterns = true; + else + props.runLIM2Patterns = false; + return true; +} + +static bool ppGetPattern(const Option *o, char *argv[]) { + props.patternFile = argv[0]; + return true; +} +// LIM2Patterns end:: + +const Option OPTIONS_OBJ [] = { + { false, "-resultsDir", 1, CL_KIND_DIR, 0, OT_WE | OT_WC, ppResultsDir, NULL, "Relative or absolute path name of the directory where the results of the analysis will be stored. The directory will be created automatically if it does not exist."}, + { false, "-projectName", 1, CL_KIND_STRING, 0, OT_WE | OT_WC, ppProjectName, NULL, "The name of the analyzed software system. The name specified here will be used for storing the results."}, + { false, "-buildScript", 1, CL_KIND_FILE, 0, OT_WE | OT_WC, ppBuildScript, NULL, "Relative or absolute path name of the build script which manages the build process of the system. If the build script does not return with 0, OpenStaticAnalyzer will stop with an error and no analysis results will be available."}, + { false, "-externalHardFilter", 1, CL_KIND_FILE, 0, OT_WE | OT_WC, ppExternalHardFilter, NULL, "Filter file specified with relative or absolute path, to filter out certain files from the analysis. Filtered files will not appear in the results. The filter file is a simple text file containing lines starting with '+' or '-' characters followed by a regular expression. During the analysis, the arguments of the wrapped commands will be checked for these expressions. If the first character of the last matching expression is '-', then the given command will not be wrapped and it will be excluded from the analysis. If the first character of the last matching expression is '+', or there is no matching expression, then the command will be wrapped. A line starting with a different character than '-' or '+' will be ignored."}, + { false, "-externalSoftFilter", 1, CL_KIND_FILE, 0, OT_WE | OT_WC, ppExternalSoftFilter, NULL, "Filter file specified with relative or absolute path to filter out source code elements (e.g. classes, methods) which are not important for some reason, but could not be filtered out via the externalHardFilter parameter. Source files containing these elements will be analyzed, but the matching results will not be calculated. The filter file is a simple text file containing lines starting with '+' or '-' characters followed by a regular expression. After the analysis, those source elements whose absolute path of their source position last matches an expression starting with '-' will not be considered in the results. If the first character of the last matching expression is '+', or there is no matching expression, then the source element will be considered as part of the software system."}, + { false, "-prefix", 1, CL_KIND_STRING, 0, OT_WE | OT_WC, ppPrefix, NULL, "We can give a certain prefix for the wrapped program names in Linux to wrapp special versions of these. If it is not set then the following commands are wrapped during the analysis:\nLinux: 'gcc', 'g++', 'c++', 'cc', 'ld', 'ar'\nWindows: 'cl', 'lib', 'link', 'clang-cl', 'lld-link', 'llvm-lib'"}, + { false, "-postfix", 1, CL_KIND_STRING, 0, OT_WE | OT_WC, ppPostfix, NULL, "We can give a certain postfix for the wrapped program names in Linux to wrapp special versions of these. If it is not set then the following commands are wrapped during the analysis:\nLinux: 'gcc', 'g++', 'c++', 'cc', 'ld', 'ar'\nWindows: 'cl', 'lib', 'link', 'clang-cl', 'lld-link', 'llvm-lib'"}, + { false, "-maximumThreads", 1, CL_KIND_NUMBER, 0, OT_WE | OT_WC, ppMaxThreads, NULL, "This parameter sets the maximum number of parallel tasks the controller can start. The default value is the number of available CPU cores on the current system."}, + { false, "-Can2LimMaxThreads", 1, CL_KIND_NUMBER, 0, OT_WE | OT_WC, ppCan2LimMaxThreads, NULL, "This parameter sets the maximum number of parallel tasks the Can2Lim task can start. The default value is the number of available CPU cores on the current system."}, + { false, "-currentDate", 1, CL_KIND_STRING, 0, OT_WE | OT_WC, ppCurrentDate, NULL, "The name of the directory with date inside the result directory of the project. If it is not set, then the current date is used."}, + { false, "-cleanResults", 1, CL_KIND_NUMBER, 0, OT_WE | OT_WC, ppCleanResults, NULL, "Cleans all but the last n number of timestamped result directory of the current project."}, + { false, "-cleanProject", 1, CL_KIND_DIR, 0, OT_WE | OT_WC, ppCleanProject, NULL, "Removes all files created during the analysis from the given directory recursively."}, + { false, "-cloneMinLines", 1, CL_KIND_NUMBER, 0, OT_WE | OT_WC, ppCloneMinLines, NULL, "This parameter sets the minimum required size of each duplication in lines of code. The default value is 10."}, + { false, "-cloneGenealogy", 1, CL_KIND_BOOL, 0, OT_WE | OT_WC, ppCloneGenealogy, NULL, "This parameter turns on or off the tracking of code clones (copy-pasted source code fragments) through the consecutive revisions of the software system. It is required that during the analysis of the different revisions, the values set to projectName and resultsDir remain the same, so OpenStaticAnalyzer will handle them as different revisions of the same system. Its value can be \"true\" (turn this feature on) or \"false\" (turn this feature off). The default value is \"false\"."}, + { false, "-csvSeparator", 1, CL_KIND_CHAR, 0, OT_WE | OT_WC, ppCsvSeparator, NULL, "This parameter sets the separator character in the CSV outputs. The default value is the comma (\",\"). The character set here must be placed in quotation marks (e.g. -csvSeparator=\";\"). Tabulator character can be set by the special \"\\t\" value."}, + { false, "-csvDecimalMark", 1, CL_KIND_CHAR, 0, OT_WE | OT_WC, ppCsvDecimalMark, NULL, "This parameter sets the decimal mark character in the CSV outputs. The default is value is the dot (\".\"). The character set here must be placed in quotation marks (e.g. -csvDecimalMark=\",\")."}, + { false, "-runCppcheck", 1, CL_KIND_BOOL, 0, OT_WE | OT_WC, ppCppcheck, NULL, "This parameter turns on or off the Cppcheck coding rule violation checking. With this feature, OpenStaticAnalyzer lists coding rule violations detected by Cppcheck. Its value can be \"true\" (turn this feature on) or \"false\" (turn this feature off). The default value is \"true\"."}, + { false, "-runClangTidy", 1, CL_KIND_BOOL, 0, OT_WE | OT_WC, ppClangTidy, NULL, "This parameter turns on or off the Clang-tidy coding rule violation checking. With this feature, OpenStaticAnalyzer lists coding rule violations detected by Clang-tidy. Its value can be \"true\" (turn this feature on) or \"false\" (turn this feature off). The default value is \"true\"."}, + { false, "-runMetricHunter", 1, CL_KIND_BOOL, 0, OT_WE | OT_WC, ppRunMetricHunter, NULL, "This parameter turns on or off the MetricHunter module. With this feature, OpenStaticAnalyzer lists metric threshold violations. Its value can be \"true\" (turn this feature on) or \"false\" (turn this feature off). The default value is \"true\""}, + { false, "-runDCF", 1, CL_KIND_BOOL, 0, OT_WE | OT_WC, ppRunDCF, NULL, "This parameter turns on or off the DuplicatedCodeFinder module. With this feature, OpenStaticAnalyzer identifies copy-pasted code fragments. Its value can be \"true\" (turn this feature on) or \"false\" (turn this feature off). The default value is \"true\""}, + { false, "-runMET", 1, CL_KIND_BOOL, 0, OT_WE | OT_WC, ppRunMET, NULL, "This parameter turns on or off the Metric module. With this feature, OpenStaticAnalyzer computes source code metrics. Its value can be \"true\" (turn this feature on) or \"false\" (turn this feature off). The default value is \"true\""}, + { false, "-profileXML", 1, CL_KIND_FILE, 0, OT_WE | OT_WC, ppProfileXML, NULL, "Global configuration file for OpenStaticAnalyzer. Its 'tool-options' tag can be used to override the default metric thresholds for the MetricHunter tool. Furthermore, its 'rule-options' tag can enable/disable or modify the priorities of multiple rules."}, + { false, "-rulesCSV", 1, CL_KIND_FILE, 0, OT_WE | OT_WC, ppRulesCSV, NULL, "There are certain rule violations that are computed by more than one tool. E.g. OETS (Operator Eq To Self) is checked by both Cppcheck and FaultHunter. In these cases, in order to avoid duplications, there is a priority order among the tools. This parameter can be used to override these default priorizations by specifying a .csv file."}, + { false, "-faultTolerant", 1, CL_KIND_BOOL, 0, OT_WE | OT_WC, ppFaultTolerant, NULL, "This parameter turns on or off the fault tolerant mode. In fault tolerant mode if any non critical error happens, then the analysis will continue and some of the results will be generated. Its value can be \"true\" (turn this feature on) or \"false\" (turn this feature off). The default value is \"true\""}, + { false, "-noDelayedTemplateParsing", 0, "", 0, OT_NONE, ppNoDelayedTemplateParsing, NULL, "This parameter disables the emulation of the cl function template definition parsing behaviour. This allows function template definitions to be analyzed." }, + { false, "-runLIM2Patterns", 1, CL_KIND_BOOL, 0, OT_WE | OT_WC, ppRunLIM2Patterns, NULL, "Run LIM2Patterns." }, + CL_SONAR2GRAPH_RUN + CL_SONAR2GRAPH_ARGS + CL_UDM_OPTIONS + CL_SARIFSEVERITY + CL_LIM2PATTERNS + CL_VERBOSE + CL_MESSAGELEVEL + CL_HELP + CL_VERSION + CL_LAST +}; + +#define DUMP_PROPERTY_PATH(name) WriteMsg::write(WriteMsg::mlDebug, " " #name "=[%s]\n", props.name.string().c_str()) +#define DUMP_PROPERTY_STRING(name) WriteMsg::write(WriteMsg::mlDebug, " " #name "=[%s]\n", props.name.c_str()) +#define DUMP_PROPERTY_INT(name) WriteMsg::write(WriteMsg::mlDebug, " " #name "=%d\n", props.name) +#define DUMP_PROPERTY_CHAR(name) WriteMsg::write(WriteMsg::mlDebug, " " #name "=%c\n", props.name) + +void dumpProperties() { + DUMP_PROPERTY_PATH(startCurrentDir); + DUMP_PROPERTY_PATH(toolchainDir); + DUMP_PROPERTY_PATH(wrapperDir); + DUMP_PROPERTY_PATH(wrapperBinDir); + DUMP_PROPERTY_PATH(toolsDir); + DUMP_PROPERTY_PATH(resultsDir); + DUMP_PROPERTY_PATH(buildScript); + DUMP_PROPERTY_PATH(currentDate); + DUMP_PROPERTY_PATH(projectResultDir); + DUMP_PROPERTY_PATH(projectTimedResultDir); + DUMP_PROPERTY_PATH(logDir); + DUMP_PROPERTY_PATH(tempDir); + DUMP_PROPERTY_PATH(asgDir); + DUMP_PROPERTY_PATH(columbusWrapperTmpDir); + DUMP_PROPERTY_PATH(externalHardFilter); + DUMP_PROPERTY_PATH(externalSoftFilter); + DUMP_PROPERTY_STRING(projectName); + DUMP_PROPERTY_STRING(prefix); + DUMP_PROPERTY_STRING(postfix); + DUMP_PROPERTY_STRING(analysisOutputDir); + DUMP_PROPERTY_INT(cleanProject); + DUMP_PROPERTY_INT(cloneGenealogy); + DUMP_PROPERTY_INT(maxThreads); + DUMP_PROPERTY_CHAR(csvSeparator); + DUMP_PROPERTY_CHAR(csvDecimalmark); + DUMP_PROPERTY_PATH(projectBaseDir); + DUMP_PROPERTY_PATH(profileXML); + DUMP_PROPERTY_PATH(rulesCSV); + DUMP_PROPERTY_INT(runCppcheck); + DUMP_PROPERTY_INT(runClangTidy); + DUMP_PROPERTY_INT(runLimMetrics); + DUMP_PROPERTY_INT(runDCF); + DUMP_PROPERTY_INT(runMetricHunter); + DUMP_PROPERTY_INT(runUDM); + DUMP_PROPERTY_INT(runUDMExplicit); + DUMP_PROPERTY_INT(cloneMinLines); + DUMP_PROPERTY_INT(runLIM2Patterns); +} + +bool checkIfBinaryInPackage(const string& toolName) { + return exists(props.toolsDir / (toolName + BINARYEXT)); +} + + +void checkUserProperties() +{ + if(props.resultsDir.empty()) + { + WriteMsg::write(WriteMsg::mlError, "Please set the resultsDir parameter. Under this directory a new directory with the name of the analyzed project will be created, if it does not exist yet. All results will be stored there under separate directories with their names containing the date and time.\n"); + clError(); + } + + if(props.projectName.empty()) + { + WriteMsg::write(WriteMsg::mlError, "Please set the projectName parameter to the name of the analyzed software system.\n"); + clError(); + } + + if(props.buildScript.empty()) + { + WriteMsg::write(WriteMsg::mlError, "Please set the buildScript parameter. This is the script, which will build the project.\n"); + clError(); + } + + props.resultsDir = system_complete(props.resultsDir); + props.buildScript = canonical(props.buildScript).make_preferred(); + + if ( !props.projectBaseDir.empty() ) + props.projectBaseDir = canonical(props.projectBaseDir).make_preferred(); + + if (props.currentDate.empty()) + props.currentDate = common::getCurrentTimeAndDate("%Y-%m-%d-%H-%M-%S"); // pattern="yyyy-MM-dd-HH-mm-ss" + + props.projectResultDir = props.resultsDir / props.projectName / "cpp"; + props.projectTimedResultDir = props.projectResultDir / props.currentDate; + + const path smDir = "openstaticanalyzer"; + + props.logDir = props.projectTimedResultDir / smDir / "log"; + props.tempDir = props.projectTimedResultDir / smDir / "temp"; + props.asgDir = props.projectTimedResultDir / smDir / "asg"; + props.graphDir = props.projectTimedResultDir / smDir / "graph"; + props.columbusWrapperTmpDir = props.tempDir / "wrapper"; + props.columbusWrapperTmpDirName = smDir / "temp" / "wrapper"; + + if ( !props.externalHardFilter.empty() ) + props.externalHardFilter = system_complete(props.externalHardFilter); + if ( !props.externalSoftFilter.empty() ) + props.externalSoftFilter = system_complete(props.externalSoftFilter); + + if (props.maxThreads == 0) + props.maxThreads = columbus::thread::ThreadPool::getNumberOfCores(); + + if (props.cleanResults < -1) + props.cleanResults = -1; + + + if (props.rulesCSV.empty()) + props.rulesCSV = props.toolsDir / "rules_cpp.csv"; + + props.runCppcheck = props.runCppcheck && checkIfBinaryInPackage("Cppcheck2Graph"); + props.runLimMetrics = props.runLimMetrics && checkIfBinaryInPackage("LIM2Metrics"); + props.runDCF = props.runDCF && checkIfBinaryInPackage("DuplicatedCodeFinder"); + props.runMetricHunter = props.runMetricHunter && checkIfBinaryInPackage("MetricHunter"); + props.runLIM2Patterns = props.runLIM2Patterns && checkIfBinaryInPackage("LIM2Patterns"); + +} + + +void initializeProperties() { + props.startCurrentDir = current_path(); + + char* baseDir = std::getenv("CODE_ANALIZER_BASE_DIR"); + if ( baseDir ) { + props.toolchainDir = path(baseDir); + } else { + props.toolchainDir = path(common::getExecutableProgramDir()); + } +#if defined(_WIN32) + string platform = "Windows"; +#elif defined(__APPLE__) + string platform = "Darwin"; +#else + string platform = "Linux"; +#endif + + props.wrapperDir = props.toolchainDir / (platform + "Wrapper") ; + props.wrapperBinDir = props.wrapperDir / "WrapperBins"; + props.wrapperToolsDir = props.wrapperBinDir / "Tools"; + + props.toolsDir = props.toolchainDir / (platform + "Tools"); + + if (common::setEnvironmentVariable(OPENSTATICANALYZER_IS_ACTIVE, "true") != 0) { + WriteMsg::write(CMSG_ENV_VAR_SET_ERROR, OPENSTATICANALYZER_IS_ACTIVE); + exit(EXIT_FAILURE); + } + + if (common::setEnvironmentVariable(LIBCLANG_ALLOW_PCH_WITH_ERRORS_VAR, "1") != 0) + { + WriteMsg::write(CMSG_ENV_VAR_SET_ERROR, LIBCLANG_ALLOW_PCH_WITH_ERRORS_VAR); + exit(EXIT_FAILURE); + } +} + +void makedirs() +{ + boost::system::error_code errorcode; + remove_all(props.projectTimedResultDir, errorcode); + if(errorcode.value() != boost::system::errc::success){ + WriteMsg::write(WriteMsg::mlError, CMSG_ERROR_DELETE_DIR, props.projectTimedResultDir.string().c_str(), errorcode.message().c_str()); + exit(EXIT_FAILURE); + } + if(!create_directories(props.projectTimedResultDir)){ + WriteMsg::write(WriteMsg::mlError, CMSG_ERROR_CREATE_DIR, props.projectTimedResultDir.string().c_str()); + exit(EXIT_FAILURE); + } + if(!create_directories(props.logDir)){ + WriteMsg::write(WriteMsg::mlError, CMSG_ERROR_CREATE_DIR, props.logDir.string().c_str()); + exit(EXIT_FAILURE); + } + if(!create_directories(props.tempDir)){ + WriteMsg::write(WriteMsg::mlError, CMSG_ERROR_CREATE_DIR, props.tempDir.string().c_str()); + exit(EXIT_FAILURE); + } + if(!create_directories(props.asgDir)){ + WriteMsg::write(WriteMsg::mlError, CMSG_ERROR_CREATE_DIR, props.asgDir.string().c_str()); + exit(EXIT_FAILURE); + } + if(!create_directories(props.graphDir)){ + WriteMsg::write(WriteMsg::mlError, CMSG_ERROR_CREATE_DIR, props.graphDir.string().c_str()); + exit(EXIT_FAILURE); + } +} + +int runAnalyzeMode() +{ + columbus::thread::ThreadPool threadPool(props.maxThreads); + Controller ctrl(props, threadPool); + list inactives; + + ctrl.addTask(new CleanupTask(props)); + + ctrl.addTask(new WrapperTask(props)); + ctrl.addTask(new LinkStaticLibsTask(props)); + + ctrl.addTask(new Can2limTask(props)); + + ctrl.addTask(new ProfileTask(props)); + + // skipping UDM can only be decided here if it's explicit on the command line + // otherwise, we run it, and it exits, if there was nothing to do according to the profile + if (!props.runUDMExplicit || props.runUDM) + ctrl.addTask(new UserDefinedMetricsTask(inactives, props)); + else + inactives.push_back("UserDefinedMetrics"); + + if (props.runCppcheck) + ctrl.addTask(new Cppcheck2GraphTask(props)); + else + inactives.push_back("Cppcheck2Graph"); + + if (props.runLimMetrics) + ctrl.addTask(new Lim2metricsTask(props)); + else + inactives.push_back("LIM2Metrics"); + + if (props.runDCF) + ctrl.addTask(new DcfTask(props)); + else + inactives.push_back("DuplicatedCodeFinder"); + + if (props.runClangTidy) + ctrl.addTask(new ClangTidyTask(props, threadPool)); + else + inactives.push_back("ClangTidyTask"); + + ctrl.addTask(new GraphMergeTask(props)); + + if (props.runMetricHunter) + ctrl.addTask(new MetricHunterTask(props)); + else + inactives.push_back("MetricHunter"); + + ctrl.addTask(new GraphDumpTask(props)); + + if (props.runLIM2Patterns) + ctrl.addTask(new LIM2PatternsTask(props)); + else + inactives.push_back("LIM2Patterns"); + + if (props.cleanResults != -1) + ctrl.addTask(new CleanResultsTask(props)); + + if (props.cleanProject) + ctrl.addTask(new CleanProjectTask(props)); + + if (props.runSonar2Graph) { + ctrl.addTask(new Sonar2GraphTask(props)); + } + + if (props.faultTolerantMode) + return ctrl.executeTasks(Controller::EM_FAIL_ON_CRITICAL_ERROR_ONLY); + else + return ctrl.executeTasks(Controller::EM_FAIL_ON_ANY_ERROR); +} + + +int main(int argc, char* argv[]) +{ + int ret = 0; + MAIN_BEGIN + + WriteMsg::setAutomaticFlush(true); + + MainInit(argc, argv, "-"); + + initializeProperties(); + + checkUserProperties(); + dumpProperties(); + + makedirs(); + logEnvironment(props); + logCommandLineArguments(props, argc, argv); + + ret = runAnalyzeMode(); + + MAIN_END + return ret; +} + diff --git a/cl/OpenStaticAnalyzerJavaScript/inc/Properties.h b/cl/OpenStaticAnalyzerJavaScript/inc/Properties.h index 1535dd5..873edba 100644 --- a/cl/OpenStaticAnalyzerJavaScript/inc/Properties.h +++ b/cl/OpenStaticAnalyzerJavaScript/inc/Properties.h @@ -33,7 +33,7 @@ typedef struct WrappedTool { struct Properties : public columbus::controller::BaseProperties { - Properties() : + Properties() : cloneGenealogy(false), cloneMinLines(-1), csvSeparator(','), @@ -46,10 +46,11 @@ struct Properties : public columbus::controller::BaseProperties runMetricHunter(true), runUDM(false), runUDMExplicit(false), + moduleBasedAnalysis(false), analysisOutputDir(".columbus_javascript"), runLIM2Patterns(true) {} - + bool cloneGenealogy; // Create clone genealogy or no. int cloneMinLines; // @@ -68,6 +69,7 @@ struct Properties : public columbus::controller::BaseProperties bool runMetricHunter; // Run MetricHunter. bool runUDM; // Run UserDefinedMetrics bool runUDMExplicit; // Was the "runUDM" switch explicitly set on the command line? + bool moduleBasedAnalysis; // Whether the input should handled as a module or just a collection of scripts (modules have properly configured package.json) std::string analysisOutputDir; // The name of the output directory (.columbus_javascript) @@ -77,7 +79,7 @@ struct Properties : public columbus::controller::BaseProperties boost::filesystem::path startCurrentDir; // Absolute path of the current directory when the CAC was started boost::filesystem::path toolchainDir; // Absolute path of the directory of the CA toolchain boost::filesystem::path toolsDir; // Absolute path of the directory of the tools inside the CA package - + boost::filesystem::path resultsDir; // Absolute path of the result directory given by the user boost::filesystem::path currentDate; // The current date boost::filesystem::path projectResultDir; // resultsDir / projectName / diff --git a/cl/OpenStaticAnalyzerJavaScript/rules_javascript.csv b/cl/OpenStaticAnalyzerJavaScript/rules_javascript.csv index 72482bd..939e1e8 100644 --- a/cl/OpenStaticAnalyzerJavaScript/rules_javascript.csv +++ b/cl/OpenStaticAnalyzerJavaScript/rules_javascript.csv @@ -247,4 +247,3 @@ SIMP;1 SIMD;1 TECS;1 YSSP;1 - diff --git a/cl/OpenStaticAnalyzerJavaScript/src/Task.cpp b/cl/OpenStaticAnalyzerJavaScript/src/Task.cpp index 9e9d725..f88ce80 100644 --- a/cl/OpenStaticAnalyzerJavaScript/src/Task.cpp +++ b/cl/OpenStaticAnalyzerJavaScript/src/Task.cpp @@ -249,7 +249,7 @@ Task::ExecutionResult RunESLintTask::execute() if (!props.profileXML.empty()) { sv.push_back("--rul"); - const string rul = (props.tempDir / "ESLint.rul").string(); + const string rul = (props.tempDir / "TSLint.rul").string(); sv.push_back(rul); } @@ -257,6 +257,10 @@ Task::ExecutionResult RunESLintTask::execute() const string out = (props.tempDir / (props.projectName + "-ESLint-result.xml")).string(); sv.push_back(out); + if (props.moduleBasedAnalysis) { + sv.push_back("-moduleBasedAnalysis"); + } + const string baseDir = (props.projectBaseDir).string(); sv.push_back(baseDir); @@ -319,7 +323,7 @@ Task::ExecutionResult ESLint2GraphTask::execute() sv.push_back("-out:" + (props.projectTimedResultDir / (props.projectName + "-ESLint.txt")).string()); sv.push_back("-lim:" + (props.asgDir / (props.projectName + ".lim")).string()); sv.push_back("-exportrul"); - sv.push_back("-rul:" + (props.tempDir / "ESLint.rul").string()); + sv.push_back("-rul:" + (props.tempDir / "TSLint.rul").string()); sv.push_back((props.tempDir / (props.projectName + "-ESLint-result.xml")).string()); checkedExec(props.toolsDir / "ESLint2Graph", sv, logger); @@ -552,10 +556,10 @@ Task::ExecutionResult ProfileTask::execute() try { // original rul files - path ESLintRulFileOrig = props.toolsDir / "ESLint.rul"; + path ESLintRulFileOrig = props.toolsDir / "TSLint.rul"; // temp rul files - path ESLintRulFile = props.tempDir / "ESLint.rul"; + path ESLintRulFile = props.tempDir / "TSLint.rul"; // data ProfileHandler profile; diff --git a/cl/OpenStaticAnalyzerJavaScript/src/main.cpp b/cl/OpenStaticAnalyzerJavaScript/src/main.cpp index ea85faa..056f55e 100644 --- a/cl/OpenStaticAnalyzerJavaScript/src/main.cpp +++ b/cl/OpenStaticAnalyzerJavaScript/src/main.cpp @@ -37,7 +37,7 @@ #define PROGRAM_NAME "OpenStaticAnalyzer for JavaScript" #define EXECUTABLE_NAME "OpenStaticAnalyzerJavaScript" -#define REQUIRED_NODE_VER 8 +#define REQUIRED_NODE_VER 12 #include "MainCommon.h" @@ -112,9 +112,9 @@ bool ppCsvDecimalMark (const common::Option *o, char *argv[]) { bool ppCsvSeparator (const common::Option *o, char *argv[]) { if (strcmp(argv[0], "\\t") == 0) props.csvSeparator = '\t'; - else if (argv[0] != 0) + else if (argv[0] != 0) props.csvSeparator = argv[0][0]; - + return true; } @@ -140,6 +140,14 @@ bool ppRunMET(const common::Option *o, char *argv[]) { return true; } +bool ppModuleBasedAnalysis(const common::Option *o, char *argv[]) { + props.moduleBasedAnalysis = false; + if (strcmp(argv[0], "true") == 0) { + props.moduleBasedAnalysis = true; + } + return true; +} + bool ppRunMetricHunter(const common::Option *o, char *argv[]) { if (strcmp(argv[0], "true") == 0) props.runMetricHunter = true; @@ -286,7 +294,7 @@ static bool ppGetPattern(const Option *o, char *argv[]) { } // LIM2Patterns end:: -const Option OPTIONS_OBJ [] = { +const Option OPTIONS_OBJ [] = { { false, "-resultsDir", 1, CL_KIND_DIR, 0, OT_WE | OT_WC, ppResultsDir, NULL, "Relative or absolute path name of the directory where the results of the analysis will be stored. The directory will be created automatically if it does not exist."}, { false, "-projectName", 1, CL_KIND_STRING, 0, OT_WE | OT_WC, ppProjectName, NULL, "The name of the analyzed software system. The name specified here will be used for storing the results."}, { false, "-externalHardFilter", 1, CL_KIND_FILE, 0, OT_WE | OT_WC, ppExternalHardFilter, NULL, "Filter file specified with relative or absolute path, to filter out certain files from the analysis based on their path names. Filtered files will not appear in the results. The filter file is a simple text file containing lines starting with '+' or '-' characters followed by a regular expression. During the analysis, each input file will be checked for these expressions. If the first character of the last matching expression is '-', then the given file will be excluded from the analysis. If the first character of the last matching expression is '+', or there is no matching expression, then the file will be analyzed. A line starting with a different character than '-' or '+' will be ignored."}, @@ -297,24 +305,25 @@ const Option OPTIONS_OBJ [] = { { false, "-cleanResults", 1, CL_KIND_NUMBER, 0, OT_WE | OT_WC, ppCleanResults, NULL, "Cleans all but the last n number of timestamped result directory of the current project."}, { false, "-cleanProject", 1, CL_KIND_BOOL, 0, OT_WE | OT_WC, ppCleanProject, NULL, "Removes all files (from the directory set by the projectBaseDir parameter) created during the analysis, but does not remove anything from the results directory (resultsDir). Its value can be \"true\" (turn this feature on, setting projectBaseDir is mandatory in this case) or \"false\" (turn this feature off). The default value is \"false\"."}, { false, "-projectBaseDir", 1, CL_KIND_DIR, 0, OT_WE | OT_WC, ppBaseDir, NULL, "Directory of the source code to be analyzed specified with relative or absolute path. Using this option the directory analysis mode will be activated. Setting projectBaseDir is mandatory."}, - - { false, "-JSANOptions", 1, CL_KIND_STRING, 0, OT_WE | OT_WC, ppJSANOptions, NULL, ""}, + + { false, "-JSANOptions", 1, CL_KIND_STRING, 0, OT_WE | OT_WC, ppJSANOptions, NULL, ""}, { false, "-cloneGenealogy", 1, CL_KIND_BOOL, 0, OT_WE | OT_WC, ppCloneGenealogy, NULL, "This parameter turns on or off the tracking of code clones (copy-pasted source code fragments) through the consecutive revisions of the software system. It is required that during the analysis of the different revisions, the values set to projectName and resultsDir remain the same, so OpenStaticAnalyzer will handle them as different revisions of the same system. Its value can be \"true\" (turn this feature on) or \"false\" (turn this feature off). The default value is \"false\"."}, { false, "-csvSeparator", 1, CL_KIND_CHAR, 0, OT_WE | OT_WC, ppCsvSeparator, NULL, "This parameter sets the separator character in the CSV outputs. The default value is the comma (\",\"). The character set here must be placed in quotation marks (e.g. -csvSeparator=\";\"). Tabulator character can be set by the special \"\\t\" value."}, { false, "-csvDecimalMark", 1, CL_KIND_CHAR, 0, OT_WE | OT_WC, ppCsvDecimalMark, NULL, "This parameter sets the decimal mark character in the CSV outputs. The default is value is the dot (\".\"). The character set here must be placed in quotation marks (e.g. -csvDecimalMark=\",\")."}, { false, "-cloneMinLines", 1, CL_KIND_NUMBER, 0, OT_WE | OT_WC, ppCloneMinLines, NULL, "This parameter sets the minimum required size of each duplication in lines of code. The default value is 10."}, { false, "-runESLint", 1, CL_KIND_BOOL, 0, OT_WE | OT_WC, ppRunESLint, NULL, "This parameter turns on or off the ESLint coding rule violation checking. With this feature, OpenStaticAnalyzer lists coding rule violations detected by ESLint, such as unused variables, empty catch blocks, etc. Its value can be \"true\" (turn this feature on) or \"false\" (turn this feature off). The default value is \"true\"."}, - + { false, "-runDCF", 1, CL_KIND_BOOL, 0, OT_WE | OT_WC, ppRunDCF, NULL, "This parameter turns on or off the DulpicatedCodeFinder module. With this feature, OpenStaticAnalyzer lists metric threshold violations. Its value can be \"true\" (turn this feature on) or \"false\" (turn this feature off). The default value is \"true\""}, { false, "-runMET", 1, CL_KIND_BOOL, 0, OT_WE | OT_WC, ppRunMET, NULL, "This parameter turns on or off the MetricsCalculator module. With this feature, OpenStaticAnalyzer lists metric threshold violations. Its value can be \"true\" (turn this feature on) or \"false\" (turn this feature off). The default value is \"true\""}, { false, "-runMetricHunter", 1, CL_KIND_BOOL, 0, OT_WE | OT_WC, ppRunMetricHunter, NULL, "This parameter turns on or off the MetricHunter module. With this feature, OpenStaticAnalyzer lists metric threshold violations. Its value can be \"true\" (turn this feature on) or \"false\" (turn this feature off). The default value is \"true\"" }, + { false, "-moduleBasedAnalysis", 1, CL_KIND_BOOL, 0, OT_WE | OT_WC, ppModuleBasedAnalysis, NULL, "This parameter turns on or off the module-based analysis. Module-based analysis takes package.json and its content into account while analyzing the project. The default value is \"false\"." }, { false, "-profileXML", 1, CL_KIND_FILE, 0, OT_WE | OT_WC, ppProfileXML, NULL, "Global configuration file for OpenStaticAnalyzer. Its tool-options tag can be used to override the default metric thresholds for the MetricHunter tool or define custom metric formulas for the UserDefinedMetrics tool. Furthermore, its rule-options tag can enable/disable or modify the priorities of multiple rules." }, { true, "-rulesCSV", 1, CL_KIND_FILE, 0, OT_WE | OT_WC, ppRulesCSV, NULL, "Set the rules csv." }, { false, "-runLIM2Patterns", 1, CL_KIND_BOOL, 0, OT_WE | OT_WC, ppRunLIM2Patterns, NULL, "Run LIM2Patterns." }, - + CL_SONAR2GRAPH_RUN CL_SONAR2GRAPH_ARGS CL_UDM_OPTIONS @@ -358,6 +367,7 @@ void dumpProperties() { DUMP_PROPERTY_INT(runESLint); DUMP_PROPERTY_INT(runUDM); DUMP_PROPERTY_INT(runUDMExplicit); + DUMP_PROPERTY_INT(moduleBasedAnalysis); DUMP_PROPERTY_PATH(rulesCSV); DUMP_PROPERTY_INT(runLIM2Patterns); } @@ -395,12 +405,12 @@ void checkUserProperties() if (props.currentDate.empty()) props.currentDate = common::getCurrentTimeAndDate("%Y-%m-%d-%H-%M-%S"); // pattern="yyyy-MM-dd-HH-mm-ss" - + props.projectResultDir = props.resultsDir / props.projectName / "javascript"; props.projectTimedResultDir = props.projectResultDir / props.currentDate; const path osaDir = "openstaticanalyzer"; - + props.logDir = props.projectTimedResultDir / osaDir / "log"; props.tempDir = props.projectTimedResultDir / osaDir / "temp"; props.asgDir = props.projectTimedResultDir / osaDir / "asg"; @@ -408,13 +418,13 @@ void checkUserProperties() if ( !props.externalHardFilter.empty() ) props.externalHardFilter = system_complete(props.externalHardFilter); - + if (props.maxThreads == 0) props.maxThreads = columbus::thread::ThreadPool::getNumberOfCores(); - + if (props.cleanResults < -1) props.cleanResults = -1; - + if (props.rulesCSV.empty()) props.rulesCSV = props.toolsDir / "rules_javascript.csv"; @@ -430,11 +440,11 @@ void checkUserProperties() void initializeProperties() { props.startCurrentDir = current_path(); - + char* baseDir = std::getenv("CODE_ANALIZER_BASE_DIR"); if ( baseDir ) { props.toolchainDir = path(baseDir); - + } else { props.toolchainDir = path(common::getExecutableProgramDir()); } @@ -444,13 +454,13 @@ void initializeProperties() { #else string platform = "Linux"; #endif - + props.toolsDir = props.toolchainDir / "Tools"; stringstream outStream; string tmpStr; std::smatch result; - + outStream.str(string()); outStream.clear(); tmpStr.clear(); @@ -508,11 +518,11 @@ void makedirs() } } -int runAnalyzeMode() +int runAnalyzeMode() { columbus::thread::ThreadPool threadPool(props.maxThreads); Controller ctrl(props, threadPool); - + if (props.cleanResults != -1) ctrl.addTask(new CleanResultsTask(props)); @@ -581,10 +591,10 @@ int main(int argc, char* argv[]) MainInit(argc, argv, "-"); initializeProperties(); - + checkUserProperties(); dumpProperties(); - + makedirs(); logEnvironment(props); logCommandLineArguments(props, argc, argv); diff --git a/cl/PAN/inc/VisitorType.h b/cl/PAN/inc/VisitorType.h index 85a57e9..2189479 100644 --- a/cl/PAN/inc/VisitorType.h +++ b/cl/PAN/inc/VisitorType.h @@ -42,7 +42,6 @@ class VisitorType : public VisitorAbstractNodes { std::list< NodeId > module_scope; std::list< NodeId > scope; std::string attribute; - NodeId currentObject; VisitedType filter; std::set< NodeId > import_resolved; diff --git a/cl/PAN/src/main.cpp b/cl/PAN/src/main.cpp index 0066e2a..5033553 100644 --- a/cl/PAN/src/main.cpp +++ b/cl/PAN/src/main.cpp @@ -493,7 +493,7 @@ int main(int argc, char** argv) if (!ofs.is_open()) { WriteMsg::write(CMSG_CANNOT_OPEN_FILE, pmlFile.c_str()); } else { - VisitorPYTHONML* visitor = new VisitorPYTHONML(ofs, "", NULL, false); + VisitorPYTHONML* visitor = new VisitorPYTHONML(ofs, "", false, false); AlgorithmPreorder ap; ap.run(*factory, *visitor); delete visitor; diff --git a/cl/ParamCheck/CMakeLists.txt b/cl/ParamCheck/CMakeLists.txt new file mode 100644 index 0000000..ab54561 --- /dev/null +++ b/cl/ParamCheck/CMakeLists.txt @@ -0,0 +1,12 @@ +set (PROGRAM_NAME ParamCheck) + +set (SOURCES + main.cpp + + messages.h +) + +add_executable(${PROGRAM_NAME} ${SOURCES}) +add_dependencies(${PROGRAM_NAME} ${COLUMBUS_GLOBAL_DEPENDENCY}) +target_link_libraries(${PROGRAM_NAME} common ${COMMON_EXTERNAL_LIBRARIES}) +set_visual_studio_project_folder(${PROGRAM_NAME} TRUE) diff --git a/cl/ParamCheck/main.cpp b/cl/ParamCheck/main.cpp new file mode 100644 index 0000000..742bbd5 --- /dev/null +++ b/cl/ParamCheck/main.cpp @@ -0,0 +1,67 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include +#include +#include +#include +#include +#include "messages.h" +using namespace std; + + +void dumpParameters(const char *params) { + vector args; + common::splitArgs(params, args); + bool include = false; + for (vector::const_iterator it = args.begin(); it != args.end(); ++it) { + if (it->find("-D") == 0) { + size_t eqpos = it->find_first_of('='); + string macro = it->substr(2, eqpos - 2); + string value; + if (eqpos != string::npos) + value = it->substr(eqpos + 1); + + printf( CMSG_DEFINE, macro.c_str(), value.c_str()); + } else if (*it == "-I") { + include = true; + + } else if (include) { + include = false; + printf( CMSG_STRING, it->c_str()); + } + + } +} + +int main(int argc, char* argv[]) { + + char *params; + + if ((params = getenv("MSC_CMD_FLAGS")) != NULL) { + dumpParameters(params); + } + + if ((params = getenv("MSC_IDE_FLAGS")) != NULL) { + dumpParameters(params); + } + + return 0; +} diff --git a/javascript/cl/JSAN/src/ast/declaration/moduleDeclaration.js b/cl/ParamCheck/messages.h similarity index 86% rename from javascript/cl/JSAN/src/ast/declaration/moduleDeclaration.js rename to cl/ParamCheck/messages.h index 9fa0aba..f794893 100644 --- a/javascript/cl/JSAN/src/ast/declaration/moduleDeclaration.js +++ b/cl/ParamCheck/messages.h @@ -18,3 +18,10 @@ * limitations under the Licence. */ +#ifndef _PARAMCHECK_H_ +#define _PARAMCHECK_H_ + +#define CMSG_DEFINE "#define %s %s\n" +#define CMSG_STRING "%s\n" + +#endif \ No newline at end of file diff --git a/cl/Sonar2Graph/src/main.cpp b/cl/Sonar2Graph/src/main.cpp index ee41246..2b5bcdd 100644 --- a/cl/Sonar2Graph/src/main.cpp +++ b/cl/Sonar2Graph/src/main.cpp @@ -590,7 +590,7 @@ bool addIssues(string commonApiCall, string key, string severity, return true; } else if (numberOfIssues > MAX_NUMBER_OF_ISSUES) { WriteMsg::write(CMSG_SONAR2GRAPH_WARNING_GREATER_THEN_IN_FILE, - numberOfIssues, key, MAX_NUMBER_OF_ISSUES); + numberOfIssues, key.c_str(), MAX_NUMBER_OF_ISSUES); if (strict) { return false; } diff --git a/cl/UserDefinedMetrics/src/UdmFunction.cpp b/cl/UserDefinedMetrics/src/UdmFunction.cpp index 1ca00a6..7dbbee6 100644 --- a/cl/UserDefinedMetrics/src/UdmFunction.cpp +++ b/cl/UserDefinedMetrics/src/UdmFunction.cpp @@ -185,10 +185,10 @@ UdmFunction::Inserter::Inserter(exprtk::symbol_table& symbolTable, min = new MIN(node, aggrCalcFors); max = new MAX(node, aggrCalcFors); - if (!symbolTable.add_function(sum->getName(), *sum)) { WriteMsg::write(CMSG_UDM_CANT_ADD_FUNCTION, sum->getName()); } - if (!symbolTable.add_function(avg->getName(), *avg)) { WriteMsg::write(CMSG_UDM_CANT_ADD_FUNCTION, avg->getName()); } - if (!symbolTable.add_function(min->getName(), *min)) { WriteMsg::write(CMSG_UDM_CANT_ADD_FUNCTION, min->getName()); } - if (!symbolTable.add_function(max->getName(), *max)) { WriteMsg::write(CMSG_UDM_CANT_ADD_FUNCTION, max->getName()); } + if (!symbolTable.add_function(sum->getName(), *sum)) { WriteMsg::write(CMSG_UDM_CANT_ADD_FUNCTION, sum->getName().c_str()); } + if (!symbolTable.add_function(avg->getName(), *avg)) { WriteMsg::write(CMSG_UDM_CANT_ADD_FUNCTION, avg->getName().c_str()); } + if (!symbolTable.add_function(min->getName(), *min)) { WriteMsg::write(CMSG_UDM_CANT_ADD_FUNCTION, min->getName().c_str()); } + if (!symbolTable.add_function(max->getName(), *max)) { WriteMsg::write(CMSG_UDM_CANT_ADD_FUNCTION, max->getName().c_str()); } } diff --git a/csharp/DefaultValues.props b/csharp/DefaultValues.props index b4a859f..2747043 100644 --- a/csharp/DefaultValues.props +++ b/csharp/DefaultValues.props @@ -4,4 +4,4 @@ ..\..\..\..\csharp-build\$(Configuration)_$(Platform) ..\..\..\..\build\bin - \ No newline at end of file + diff --git a/csharp/cl/CSAN/RoslynVisitors/RoslynVisitor.Statement.cs b/csharp/cl/CSAN/RoslynVisitors/RoslynVisitor.Statement.cs index ca95105..98dbe38 100644 --- a/csharp/cl/CSAN/RoslynVisitors/RoslynVisitor.Statement.cs +++ b/csharp/cl/CSAN/RoslynVisitors/RoslynVisitor.Statement.cs @@ -60,7 +60,7 @@ public override void VisitObjectCreationExpression( ObjectCreationExpressionSynt var pair = new KeyValuePair( id, false ); if ( !fileContext.MethodStack.Peek( ).CanThrow.Contains( pair ) ) fileContext.MethodStack.Peek( ).Instantiates.Add( pair ); - if ( symbol.Kind == SymbolKind.NamedType && synNode.Kind( ) != SyntaxKind.DelegateDeclaration ) + if ( symbol.Kind == SymbolKind.NamedType && synNode?.Kind( ) != SyntaxKind.DelegateDeclaration ) { fileContext.CrossEdgeFiller.OriginalDefinitionFiller( synNode as MemberDeclarationSyntax, node.Type ); } diff --git a/inc/ReleaseVersion.h b/inc/ReleaseVersion.h index f01395b..edde57d 100644 --- a/inc/ReleaseVersion.h +++ b/inc/ReleaseVersion.h @@ -23,6 +23,6 @@ #include "columbus_config.h" -static const char CopyRightMessage[] = "Copyright (c) 2004-2021 Department of Software Engineering - University of Szeged "; +static const char CopyRightMessage[] = "Copyright (c) 2004-2022 Department of Software Engineering - University of Szeged "; #endif diff --git a/java/cl/JAN/src/main/java/org/jan/TypeBuilder.java b/java/cl/JAN/src/main/java/org/jan/TypeBuilder.java index 0edc7b5..bb402fd 100644 --- a/java/cl/JAN/src/main/java/org/jan/TypeBuilder.java +++ b/java/cl/JAN/src/main/java/org/jan/TypeBuilder.java @@ -126,7 +126,7 @@ public void buildTypes(Map> typeMap, TypeKinds typeKind) { } break; case METHOD_TYPE: - if (b instanceof MethodDeclaration) { + if (b instanceof MethodDeclaration && Common.getIsMethodType(fact.getRef(typeId))) { MethodDeclaration m = (MethodDeclaration) b; m.setMethodType(typeId); } else { diff --git a/java/lib/openjdk b/java/lib/openjdk index 10f87bf..7143b31 160000 --- a/java/lib/openjdk +++ b/java/lib/openjdk @@ -1 +1 @@ -Subproject commit 10f87bfca8b60b5d3242720936ef94c5d6767eec +Subproject commit 7143b3183b53499440d1ce1917a42d4c84791ddf diff --git a/javascript/cl/ESLintRunner/.gitignore b/javascript/cl/ESLintRunner/.gitignore new file mode 100644 index 0000000..b947077 --- /dev/null +++ b/javascript/cl/ESLintRunner/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +dist/ diff --git a/javascript/cl/ESLintRunner/CMakeLists.txt b/javascript/cl/ESLintRunner/CMakeLists.txt index 8775df8..ab86d7d 100644 --- a/javascript/cl/ESLintRunner/CMakeLists.txt +++ b/javascript/cl/ESLintRunner/CMakeLists.txt @@ -1,16 +1,36 @@ -set (PROGRAM_NAME ESLintRunner) +set (PROGRAM_NAME eslintrunner) add_custom_target ( - ${PROGRAM_NAME} - COMMAND npm install ${MSVS_VERSION} > ${CMAKE_CURRENT_BINARY_DIR}/${PROGRAM_NAME}-build.log 2>&1 - DEPENDS javascript - WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}/node_modules/eslintrunner + ${PROGRAM_NAME}_install + COMMAND npm install > ${CMAKE_CURRENT_BINARY_DIR}/${PROGRAM_NAME}-npm-install.log 2>&1 + WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}/tmp_${PROGRAM_NAME} ) -add_custom_copy_target(${PROGRAM_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROGRAM_NAME}.js ${EXECUTABLE_OUTPUT_PATH}/node_modules/eslintrunner/${PROGRAM_NAME}.js) -add_custom_copy_target(${PROGRAM_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/src ${EXECUTABLE_OUTPUT_PATH}/node_modules/eslintrunner/src DIRECTORY) -add_custom_copy_target(${PROGRAM_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/package.json ${EXECUTABLE_OUTPUT_PATH}/node_modules/eslintrunner/package.json) -add_custom_copy_target(${PROGRAM_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/eslint.json ${EXECUTABLE_OUTPUT_PATH}/node_modules/eslintrunner/eslint.json) -add_custom_copy_target(${PROGRAM_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/OpenStaticAnalyzerFormater.js ${EXECUTABLE_OUTPUT_PATH}/node_modules/eslintrunner/OpenStaticAnalyzerFormater.js) +add_custom_copy_target(${PROGRAM_NAME}_install ${CMAKE_CURRENT_SOURCE_DIR} ${EXECUTABLE_OUTPUT_PATH}/tmp_${PROGRAM_NAME} DIRECTORY) +set_target_properties (${PROGRAM_NAME}_install PROPERTIES FOLDER ${CMAKE_SUPPORT_FOLDER_NAME}) -set_visual_studio_project_folder(${PROGRAM_NAME} TRUE) +add_custom_target ( + ${PROGRAM_NAME}_build + COMMAND npm run build -- --no-color -o ${EXECUTABLE_OUTPUT_PATH}/node_modules/${PROGRAM_NAME} > ${CMAKE_CURRENT_BINARY_DIR}/${PROGRAM_NAME}-npm-build.log 2>&1 + DEPENDS ${PROGRAM_NAME}_install + WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}/tmp_${PROGRAM_NAME} +) + +set_target_properties (${PROGRAM_NAME}_build PROPERTIES FOLDER ${CMAKE_SUPPORT_FOLDER_NAME}) + +add_custom_target( + ${PROGRAM_NAME}_modules + COMMAND ${CMAKE_COMMAND} -E copy_directory ${EXECUTABLE_OUTPUT_PATH}/tmp_${PROGRAM_NAME}/node_modules/ ${EXECUTABLE_OUTPUT_PATH}/node_modules/${PROGRAM_NAME}/node_modules/ + DEPENDS ${PROGRAM_NAME}_build +) + +add_custom_target ( + ${PROGRAM_NAME}_virtual_target + # from cmake 3.17 + # COMMAND ${CMAKE_COMMAND} -E rm -rf ${EXECUTABLE_OUTPUT_PATH}/tmp_${PROGRAM_NAME} + # until cmake 3.16 + COMMAND ${CMAKE_COMMAND} -E remove_directory -rf ${EXECUTABLE_OUTPUT_PATH}/tmp_${PROGRAM_NAME} + DEPENDS ${PROGRAM_NAME}_modules +) + +set_visual_studio_project_folder(${PROGRAM_NAME}_virtual_target TRUE) diff --git a/javascript/cl/ESLintRunner/ESLintRunner.js b/javascript/cl/ESLintRunner/ESLintRunner.js index a7604d0..cc5d748 100644 --- a/javascript/cl/ESLintRunner/ESLintRunner.js +++ b/javascript/cl/ESLintRunner/ESLintRunner.js @@ -18,27 +18,37 @@ * limitations under the Licence. */ -const clOptions = require('./src/assets/options'); -const eslint = require('eslint'); -const fs = require('fs'); -var eslintConfig; -const formatter = require('./OpenStaticAnalyzerFormater'); -const JSONStream = require('JSONStream'); -const parseXML = require('xml2js').parseString; - -var CLIEngine = eslint.CLIEngine; -var SourceCode = eslint.SourceCode; - -var ignoredFilesList = ".eslintignore"; -var globals = require('./src/globals'); -var options = clOptions.parse(); +import * as eslint from 'eslint'; +import * as clOptions from './src/assets/options.js'; +import * as fs from 'fs'; +import * as path from 'path'; +import {formatter} from "./outputFormatter.js"; +import {parseString} from 'xml2js'; +import * as globals from './src/globals.js'; +import * as constants from './src/assets/constants.js'; +import * as JSON5 from "json5"; + +/** + * The parsed command line arguments. + */ +const options = clOptions.parse(); globals.setOptions(options); -const util = require('util'); -const path = require('path'); -const espree = require('espree'); +/** + * Path for the default Typescript-ESLint configuration + * @type: {string} + */ +const defaultTSConfigurationPath = path.resolve(__dirname, "typescript-eslint.json"); +/** + * If a project wants to extend a non-existing, file it creates an empty one and stores its path in this array. + * @type: {*[]} + */ +let filesToBeDeleted = []; -var resultSet = []; +/** + * Typescript-ESLint configuration which is either from the rul file, or from the default configuration. + */ +let typescriptEslintConfig; class Memory { static init() { @@ -62,303 +72,385 @@ class Memory { Memory.init(); /** - * TODO: Delete this code once JSAN and ESLintRunner are merged - * This method make the parsing with Espree - * and generate the raw of AST. - * @param code The path of the parsable file - * @param type The code, what we want parse - * @returns {*} The result of parsing + * Parses a given .rul configuration file and transforms it into a json config object for ESLint */ -let parsingOptions; -let parseCode = function (filePath, code, type) { - const options = { - sourceType: type, - comment: true, - tolerant: true, - loc: true, - raw: true, - tokens: true, - range: true, - ecmaVersion: 2018, - attachComment: false, - }; +function externalRul(file) { + const metrics = {}; - try { - let rawAst = espree.parse(code, options); - console.log("Succesfully parsed as " + type + ": " + filePath.absolute); - return {success: true, ast: rawAst, options: options, sourceType: type}; - } catch (e) { - if (type !== 'script') { - console.log("Failed to parse as " + type + ": " + filePath.absolute); - console.error(e); - console.log("Trying to parse as script."); - return parseCode(filePath, code, 'script'); - } else { - console.log("Failed to parse: " + filePath.absolute); - console.error(e); - return {success: false, error: e}; - } + console.log("Loading external rul file (" + file + ")"); + if (!fs.existsSync(file)) { + console.log("The external rul file does not exists!") + process.exit() } - -}; - -/** - * TODO: Delete this code once JSAN and ESLintRunner are merged - * This method start the parsing of the code, - * create the ast format json and concatenate - * the filename. - * @param filePath The path of analyzeable file - * @param code The code, what we want parse - * @returns {number|*} - */ -let makeAstFromCode = function (filePath, code) { - const rawAst = parseCode(filePath, code, 'module'); + const rulContent = fs.readFileSync(file, 'utf-8'); Memory.check(); - if (rawAst.success) { - parsingOptions = rawAst.options; - let ast = rawAst.ast; - ast.filename = globals.getOption('useRelativePath') ? filePath.relative : filePath.absolute; - ast.sourceType = rawAst.sourceType; - return ast; - } else { - throw new Error('The parsing of code was unsuccessful: ' + rawAst.error); - } -}; -/** - * TODO: Delete this code once JSAN and ESLintRunner are merged - * This method start the analyze, transform the ast - * and return with results. - * @param filePath The path of analyzing file - * @param code The code, what we want analyze - * @returns {*} - */ -let makeAnalyzeCodeResult = function (filePath, code) { + let currentPointer; try { - Memory.check(); - let ast = makeAstFromCode(filePath, code); - return {success: true, ast: ast}; - } catch (e) { - return {success: false, error: e}; - } -}; - - /** - * TODO: Delete this code once JSAN and ESLintRunner are merged - * Trim shebang to avoid parse error - * Doing it this way will preserve the original absolute positions - * This snippet is taken from: https://github.com/jquery/esprima/issues/1151#issuecomment-85706244 - * @param code the loaded code that might include starting shebang - * @returns the stripped source code - */ -function trimHashbang(code) { - if (typeof code !== 'string') { - console.log("Code was not string, it was: " + code); - return code; - } - if (code.substring(0, 2) === '#!') { - let end = code.indexOf('\n'); - let filler = ''; - for (let i = 0; i < end; ++i) { - filler += ' '; - } - code = filler + code.substring(end, code.length); - console.log("Leading shebang was removed"); - } - return code; -} - -/** - * TODO: Delete this code once JSAN and ESLintRunner are merged - * The loadCode method traverse the files, which - * we gave in parameter and on each file start the - * analyzing. - * - * @param files The list of the analyzing files. - * @returns {{result: Array}} - */ -function loadCode(files) { - console.time('Total time of loading code'); - let result = []; - Memory.check(); - let successfullyParsedFiles = []; - files.forEach(function (file) { - let filePath = { - absolute: null, - relative: null - }; - if (path.isAbsolute(file)) { - filePath = { - absolute: path.normalize(file), - relative: path.relative(process.cwd(), file) - }; - } - else { - filePath = { - absolute: path.join(process.cwd(), file), - relative: path.normalize(file) - }; - } - - let code; - - globals.setActualFile(globals.getOption('useRelativePath') ? filePath.relative : filePath.absolute); - - if (!fs.existsSync(filePath.relative)) { - console.log(filePath.absolute + " does not exists. It will be omitted from the analysis"); - return; - } - - if (path.extname(filePath.relative) === '.js') { - try { - code = fs.readFileSync(filePath.absolute); - code = String(code); - } catch (err) { - console.log("Error while loading the code from file: " + filePath.absolute); + parseString(rulContent, {trim: true}, function (err, result) { + if (err) { console.log(err); - return; } - } - // Preprocessing steps - const preprocessors = [trimHashbang]; - preprocessors.forEach(function (preprocessorFunction) { - code = preprocessorFunction(code); - }); - - let analyzeResult = makeAnalyzeCodeResult(filePath, code); - if (analyzeResult.success) { - if (analyzeResult.ast.sourceType === 'module') { - successfullyParsedFiles.push(filePath.absolute); - } - result.push(analyzeResult.ast); - } else { - console.error(analyzeResult.error); - } - }); - Memory.check(); - console.timeEnd('Total time of loading code'); - return {result: result, successfullyParsedFiles: successfullyParsedFiles}; -} - -/* - * Parses a given .rul configuration file and transforms it into a json config object for ESLint - * */ -function externalRul(file) { - var metrics = {}; - try { - console.log("Loading external rul file (" + file + ")"); - var rulcontent = fs.readFileSync(file, 'utf-8'); - Memory.check(); - } catch (err) { - console.log(err); - process.exit(); - } - var currentPointer; - try { - parseXML(rulcontent, {trim: true}, function (err, result) { - if (err) - console.log(err); result.Rul.Metric.forEach(function (elem) { Memory.check(); - if (elem.Configuration[0].Group[0] == "false") { - var originalID = elem.Configuration[0].OriginalId; - var enabled = (elem.Configuration[0].Enabled[0] == "true" ? 1 : 0); - var param = null; - var settings = elem.Configuration[0].Settings[0].Setting; + if (elem.Configuration[0].Group[0] === "false") { + const originalID = elem.Configuration[0].OriginalId; + const enabled = (elem.Configuration[0].Enabled[0] === "true" ? 1 : 0); + const settings = elem.Configuration[0].Settings[0].Setting; + + let param = null; currentPointer = originalID; settings.forEach(function (setting) { - if (setting.$.name == "__eslint_param__") { + if (setting.$.name === "__eslint_param__") { param = setting._; } }); if (param) { - var ruleOptions = []; + const ruleOptions = []; ruleOptions.push(enabled); ruleOptions.push(JSON.parse(param)); metrics[originalID] = ruleOptions; - } - else { + } else { metrics[originalID] = enabled; } } Memory.check(); - }); Memory.check(); }); } catch (err) { - console.error("Syntax error around '" + currentPointer + "' metric. Please check the metric and neighbours."); + console.error(`Syntax error around '${currentPointer}' metric. Please check the metric and neighbours.`); console.error("A possible error: Maybe not valid JSAN format at __eslint_param__ setting."); - console.log("The analyze will use the default eslint.json config file. Loading.."); - return require('./eslint.json'); + console.log("The analyze will use the default typescript-eslint.json config file. Loading.."); + return readDefaultRules(); } Memory.check(); return metrics; } -function parseAst(astShadow) { - console.log("Processing " + astShadow.filename + "..."); +/** + * @path: The absolute path of the package.json file + * Reads the entire package.json and returns it as an object. + * **/ +function readPackageJSON(path) { + let data; try { - var code = new SourceCode("", astShadow); - Memory.check(); - var cli = new CLIEngine({ - parserOptions: {sourceType: astShadow.sourceType}, - baseConfig: { - env: { es6: true } - }, - useEslintrc: false, - ignore: false, - rules: eslintConfig - }); - var exec = cli.executeOnText(code, astShadow.filename); - Memory.check(); - exec.results.filename = astShadow.filename; - resultSet.push(exec.results); + data = JSON.parse(fs.readFileSync(path)); } catch (err) { - console.log(err); + console.error(err); } + return data; } -function saveToFile(outputFileShadow, finishEvent) { +function saveToFile(outputFileShadow, resultSet, finishEvent) { if (!outputFileShadow.endsWith(".xml")) { outputFileShadow += ".xml"; } - console.log("Save result into " + outputFileShadow + " file."); - var wstream = fs.createWriteStream(outputFileShadow); - wstream.write(formatter(resultSet)); + console.log(`Saving results into ${outputFileShadow}.`); + const writeStream = fs.createWriteStream(outputFileShadow); + writeStream.write(formatter(resultSet)); Memory.check(); - wstream.end(); + writeStream.end(); if (typeof finishEvent === 'function') { finishEvent(); } console.log("Done."); } +/** + * This function searches for all of the tsconfig files which exist in the current project. + * Any file that contains "tsconfig" in its name is stored in the returnableArray. + * @param: input - An absolute path, which can be a file or a directory. + * @param: returnableArray - An array that contains the paths of tsconfig files. + * @returns: returnableArray - Returns all the absolute paths of the tsconfig files. + */ +function searchFoldersForConfig(input, returnableArray) { + if (!fs.existsSync(input)) { + return returnableArray; + } + if (fs.lstatSync(input).isDirectory()) { + const dirContent = fs.readdirSync(input); + for (let i = 0; i < dirContent.length; i++) { + returnableArray = searchFoldersForConfig(path.join(input, dirContent[i]), returnableArray); + } + return returnableArray; + } else { + if (path.basename(input).search("tsconfig") === 0) { + returnableArray.push(input); + } + return returnableArray; + } +} + +/** + * This function detects if the analyzed project has a tsconfig.json file, and if not, + * creates a temporary .json file in the dist directory. + * This is necessary, as some rules cannot be used without the "include" field in said file. + * + * @param: typeScriptOptions the config for the typescript-eslint parser + * @param: tsConfigContent content of tsconfig.json in case the analyzed project has no such file + */ +function readProjectTsconfig(typeScriptOptions, tsConfigContent) { + let configPathsArray = []; + searchFoldersForConfig(globals.getOption("inputList")[0], configPathsArray); + if (configPathsArray.length > 0) { //in case at least 1 tsconfig exists within the analyzed project + //using JSON5 due to comments. + for (let index in configPathsArray) { + try { + const options = JSON5.parse(fs.readFileSync(configPathsArray[index]).toString()); + //Checks if tsconfig has exclude parameter. + if (options["exclude"] !== undefined) { + for (let i = 0; i < options["exclude"].length; i++) { + typeScriptOptions["baseConfig"]["ignorePatterns"].push(options["exclude"][i]); + } + } + //In case the tsconfig wants to extend from a non-existent file, we create an empty one. + if (options["extends"] !== undefined) { + let extendedFile = path.join(path.dirname(configPathsArray[index]), options["extends"]); + if (!fs.existsSync(extendedFile)) { + fs.writeFileSync(extendedFile, ""); + filesToBeDeleted.push(extendedFile); + } + } + typeScriptOptions["baseConfig"]["parserOptions"]["project"].push((configPathsArray[index].replace(/\\/g, '/'))); + } catch (e) { + console.log(e); + } + } + return; + } + //in case project has no tsconfig / a single file is being linted and might need type information + console.log("Creating temporary config..."); + typeScriptOptions["baseConfig"]["parserOptions"]["project"] = __dirname + '/tsconfig.json'; + if (globals.getOption(constants.MODULE_BASED_ANALYSIS) + && globals.getOption('inputList').length === 1 + && fs.existsSync(globals.getOption('inputList')[0])) { + if (path.extname(globals.getOption("inputList")[0]) === '.ts' || path.extname(globals.getOption("inputList")[0]) === '.js' || path.extname(globals.getOption("inputList")[0]) === '.tsx') { //in case a single file is being analyzed + tsConfigContent["include"].push(path.resolve(globals.getOption("inputList")[0])); + } else { //directory + tsConfigContent["include"].push(path.resolve(globals.getOption("inputList")[0]) + '/**/**.ts'); + tsConfigContent["include"].push(path.resolve(globals.getOption("inputList")[0]) + '/**/**.tsx'); + tsConfigContent["include"].push(path.resolve(globals.getOption("inputList")[0]) + '/**/**.jsx'); + tsConfigContent["include"].push(path.resolve(globals.getOption("inputList")[0]) + '/**/**.js'); + } + } else { + for (let index in globals.getOption("inputList")) { //mba is not enabled, analyzing lots of files + tsConfigContent["include"].push(path.resolve(globals.getOption("inputList")[index])); + } + } + //creates a temporary directory which contains the now created tsconfig + const tmpDir = path.resolve(path.basename(globals.getOption("inputList")[0]).replace(path.extname(globals.getOption("inputList")[0]), '')); + if (!fs.existsSync(tmpDir)) { + fs.mkdirSync((tmpDir), (err) => { + if (err) { + console.log(err) + } + }); + } else { + fs.unlinkSync(tmpDir + '/tsconfig.json'); // in case project has already been analysed, and in just in case the tsconfig.json file has changed + } + fs.writeFileSync((tmpDir + '/tsconfig.json').replace(/\\/g, '/'), JSON.stringify(tsConfigContent)); + typeScriptOptions["baseConfig"]["parserOptions"]["project"] = tmpDir + '/tsconfig.json'; +} + +/** + * Appends ignore patterns from package.json to running config. + * @packageContent: Contents of the analyzed project's eslintIgnore field in package.json + * @param: typeScriptOptions the config for the typescript-eslint parser + * */ +function appendToIgnore(packageContent, typeScriptOptions) { + for (let i in packageContent["eslintIgnore"]) { + typeScriptOptions["baseConfig"]["ignorePatterns"].push(packageContent["eslintIgnore"][i]) + } +} + +function readDefaultRules() { + if (!fs.existsSync(defaultTSConfigurationPath)) { + throw new Error("Default typescript-eslint configuration is missing!"); + } + return JSON.parse(fs.readFileSync(defaultTSConfigurationPath, "utf8")); +} + +/** + * @packageJsonPath: The absolut epath of the package.json's file. + * It reads the rules from the package.json file if it has any. + * If not it reads the built-in one. + * */ +function readRulesFromPackageJson(packageJsonPath) { + try { + if (packageJsonPath["eslintConfig"]["rules"] !== undefined) { + const packageJsonContents = readPackageJSON(packageJsonPath)["eslintConfig"]["rules"]; + if (packageJsonContents !== undefined) { + console.log("The external rul file is missing. Using rules from package.json"); + typescriptEslintConfig = packageJsonContents; + } + } + } catch { + console.log("The package.json file is missing ESLint rules. Using the built-in rules (typescript-eslint.json)."); + typescriptEslintConfig = readDefaultRules(); + } +} + /** * Runs ESLint on every input. */ function runESLint(finishEvent) { "use strict"; + //default options for the parser + + const typeScriptOptions = { // options in case package.json has no eslintConfig & typescript files are analyzed + baseConfig: { + root: true, + env: { + es2020: true, + }, + parserOptions: { + ecmaFeatures: { + jsx: false + }, + tsconfigRootDir: globals.getOption("inputList")[0], + project: [], + rules: "" + }, + overrides: [ + { + files: ["*.ts", "*.tsx"], + excludedFiles: [], + extends: [], + settings: { + import: { + parsers: { + "@typescript-eslint/parser": ["*.ts", "*.tsx"], + } + } + } + } + ], + plugins: [ + "@typescript-eslint/eslint-plugin", + "eslint-plugin-react", + "eslint-plugin-angular", + "eslint-plugin-flowtype", + "eslint-plugin-import", + "eslint-plugin-jsx-a11y", + "eslint-plugin-react-hooks" + ], + parser: "@typescript-eslint/parser", + //Certain configuration files aren't analyzed. + ignorePatterns: ["**/*.config.js", "**/*.config.ts", ".eslintrc*", "**/*.conf.js", "**/*.conf.ts", "**/*-config.js", "**/*-config.ts", "gulpfile.js"] + }, + useEslintrc: false, + globInputPaths: false, + }; + //checking if the path is a directory or a file + if (fs.existsSync(globals.getOption("inputList")[0]) && fs.lstatSync(globals.getOption("inputList")[0]).isDirectory()) { + typeScriptOptions["baseConfig"]["parserOptions"]["sourceType"] = "module"; + } else { + typeScriptOptions["baseConfig"]["parserOptions"]["sourceType"] = "script"; + typeScriptOptions["baseConfig"]["parserOptions"]["tsconfigRootDir"] = path.basename(globals.getOption("inputList")[0]); + } + //default configuration for analyzed projects + let defaultTSConfig = { + compilerOptions: { + baseUrl: "node_modules", + target: "es2020", + module: "commonjs", + moduleResolution: "node", + noEmitOnError: true, + lib: [ + "es2020" + ], + strict: true, + esModuleInterop: false, + outDir: "dist" + }, + include: [], + exclude: [ + "node_modules", + "dist" + ] + }; + readProjectTsconfig(typeScriptOptions, defaultTSConfig); + const packageJsonPath = path.join(globals.getOption("inputList")[0], "package.json"); + let packageJsonContents; + if (fs.existsSync(packageJsonPath)) { + packageJsonContents = readPackageJSON(packageJsonPath); + } + if (packageJsonContents !== undefined) { + if (packageJsonContents["eslintConfig"] !== undefined) { + for (let key in packageJsonContents["eslintConfig"]) { + typeScriptOptions["baseConfig"][key] = packageJsonContents["eslintConfig"][key]; + } + } + } + typeScriptOptions["baseConfig"]["rules"] = typescriptEslintConfig; Memory.check(); - let resultOfAnalyze = loadCode(globals.getOption('inputList')); + // If module-based analysis is set, we set the .eslintignore file to the ignore path + if (globals.getOption(constants.MODULE_BASED_ANALYSIS) + && globals.getOption('inputList').length === 1 + && fs.existsSync(globals.getOption('inputList')[0])) { + const eslintIgnorePath = path.join(globals.getOption('inputList')[0], ".eslintignore"); + if (fs.existsSync(eslintIgnorePath)) { + typeScriptOptions.ignorePath = eslintIgnorePath; + } else { + try { //check if package.json contains eslintIgnore + if (fs.existsSync(packageJsonPath)) { + let packageContent = readPackageJSON(packageJsonPath); + if (packageContent["eslintIgnore"] !== undefined) { + appendToIgnore(packageContent, typeScriptOptions); + } - resultOfAnalyze.result.forEach(function (ast) { - parseAst(ast); + } + } catch (err) { + console.log(err); + } + } + } + //if externalhardfilter was used and files were filtered + if (globals.getOption('filteredFiles').length > 0) { + for (let i in globals.getOption('filteredFiles')) { + typeScriptOptions["baseConfig"]["ignorePatterns"].push(globals.getOption('filteredFiles')[i]); + } + } + let eslintProgram = new eslint.ESLint(typeScriptOptions); + Memory.check(); + //console.debug(`Analyzing input ${globals.getOption('inputList')}`); + eslintProgram.lintFiles(globals.getOption('inputList')).then(results => { Memory.check(); + // Save raw results + if (globals.getOption(constants.RAW_OUTPUT)) { + fs.writeFile("eslint-raw-results.json", JSON.stringify(results), 'utf8', function (err) { + if (err) { + console.log("An error occurred while writing raw results to JSON file."); + return console.log(err); + } + console.log("Raw results have been saved."); + }); + } + saveToFile(options.out, results, finishEvent); + for (let dfile in filesToBeDeleted) { + console.log("anyád"); + fs.unlinkSync(filesToBeDeleted[dfile]); + } + Memory.check(); + }).catch(err => { + console.log("An error occurred while running ESLint!") + console.log(err); + }).finally(() => { + console.log("Finished!"); }); - saveToFile(options.out, finishEvent); Memory.check(); } function wrappedRunESLint() { - "use strict"; + "use strict"; const start = process.hrtime(); - var elapsed; - var sec; - var used; + let elapsed; + let sec; + let used; runESLint(function () { elapsed = process.hrtime(start); @@ -373,7 +465,7 @@ function wrappedRunESLint() { sec + ";" + Memory.result() ]; - fs.writeFile(globals.getOption("stat"), csv.join("\n"), function (err) { + fs.writeFile(globals.getOption(constants.STAT), csv.join("\n"), function (err) { if (err) throw err; }); }); @@ -388,19 +480,29 @@ function analyzeMain() { "use strict"; //Determine if default json should be used or use a rul file from which the config should be generated - if (options.rul) { - eslintConfig = externalRul(options.rul); - Memory.check(); - } else { - console.log("The external rul file is missing. Using the built-in rules (eslint.json)."); - eslintConfig = require('./eslint.json'); - } - - if (globals.getOption("stat")) { - wrappedRunESLint(); - } else { - runESLint(); + try { + const packageJsonPath = path.join(globals.getOption("inputList")[0], "package.json").toString(); + if (options.rul) { + typescriptEslintConfig = externalRul(options.rul); + Memory.check(); + } else if (fs.existsSync(packageJsonPath)) { + readRulesFromPackageJson(packageJsonPath); + } else { + console.log("The package.json file is missing. Using the built-in rules (typescript-eslint.json)."); + typescriptEslintConfig = readDefaultRules(); + } + if (globals.getOption("stat")) { + wrappedRunESLint(); + } else { + runESLint(); + } + } catch (e) { + console.log(e); } } -analyzeMain(); +try { + analyzeMain(); +} catch (e) { + console.log(e); +} diff --git a/javascript/cl/ESLintRunner/OpenStaticAnalyzerFormater.js b/javascript/cl/ESLintRunner/OpenStaticAnalyzerFormater.js deleted file mode 100644 index 0dd78a9..0000000 --- a/javascript/cl/ESLintRunner/OpenStaticAnalyzerFormater.js +++ /dev/null @@ -1,75 +0,0 @@ -/* - * This file is part of OpenStaticAnalyzer. - * - * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged - * - * Licensed under Version 1.2 of the EUPL (the "Licence"); - * - * You may not use this work except in compliance with the Licence. - * - * You may obtain a copy of the Licence in the LICENSE file or at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ - -var os = require('os'); -var path = require("path"); - -function getMessageType(message) { - if (message.fatal) - return "fatal"; - return message.severity === 2 ? "error" : "warning"; -} - -function xmlEscape(s) { - var regex = /[^\u000D\u00B7\u0020-\u007E\u00A2-\u00A4]/g; - var corrected = ("" + s).replace(/[<>&"']/g, function (c) { - switch (c) { - case "<": - return " < "; - case ">": - return " > "; - case "&": - return " & "; - case "\"": - return " " "; - case "'": - return " ' "; - // no default - } - }); - return ("" + corrected).replace(regex, ''); - -} - -//------------------------------------------------------------------------------ -// Public Interface -//------------------------------------------------------------------------------ -module.exports = function (resultset) { - var output = "" + os.EOL; - output += "" + os.EOL; - resultset.forEach(function (results) { - var pathToFile = results.filename; - results.forEach(function (result) { - output += " " + os.EOL; - result.messages.forEach(function (message) { - output += " " + os.EOL; - }); - output += " " + os.EOL; - }); - }); - output += ""; - return output; -}; \ No newline at end of file diff --git a/javascript/cl/ESLintRunner/eslint.json b/javascript/cl/ESLintRunner/eslint.json deleted file mode 100644 index 9e01020..0000000 --- a/javascript/cl/ESLintRunner/eslint.json +++ /dev/null @@ -1,353 +0,0 @@ -{ "for-direction": 0, - "getter-return": [ 0, { "allowImplicit": true } ], - "no-await-in-loop": 0, - "no-compare-neg-zero": 1, - "no-cond-assign": [ 1, "except-parens" ], - "no-console": [ 1, { "allow": [ "warn", "error" ] } ], - "no-constant-condition": [ 1, { "checkLoops": true } ], - "no-control-regex": 1, - "no-debugger": 1, - "no-dupe-args": 1, - "no-dupe-keys": 1, - "no-duplicate-case": 1, - "no-empty": [ 1, { "allowEmptyCatch": true } ], - "no-empty-character-class": 1, - "no-ex-assign": 1, - "no-extra-boolean-cast": 1, - "no-extra-parens": [ 0, "all" ], - "no-extra-semi": 1, - "no-func-assign": 1, - "no-inner-declarations": [ 1, "functions" ], - "no-invalid-regexp": - [ 1, - { "allowConstructorFlags": [ "u", "y" ] } - ], - "no-irregular-whitespace": [ 1, { "skipStrings": true } ], - "no-obj-calls": 1, - "no-prototype-builtins": 0, - "no-regex-spaces": 1, - "no-sparse-arrays": 1, - "no-template-curly-in-string": 0, - "no-unexpected-multiline": 1, - "no-unreachable": 1, - "no-unsafe-finally": 1, - "no-unsafe-negation": 1, - "use-isnan": 1, - "valid-jsdoc": [ 0, { "requireReturn": false } ], - "valid-typeof": [ 1, { "requireStringLiterals": true } ], - "accessor-pairs": [ 0, { "setWithoutGet": true, "getWithoutSet": false } ], - "array-callback-return": [ 0, { "allowImplicit": false } ], - "block-scoped-var": 0, - "class-methods-use-this": 0, - "complexity": [ 0, { "max": 2 } ], - "consistent-return": [ 0, { "treatUndefinedAsUnspecified": false } ], - "curly": [ 0, "all" ], - "default-case": [ 0, { "commentPattern": "/^no default$/i" } ], - "dot-location": [ 0, "object" ], - "dot-notation": [ 0, { "allowKeywords": true } ], - "eqeqeq": [ 1, "always" ], - "guard-for-in": 0, - "no-alert": 0, - "no-caller": 0, - "no-case-declarations": 1, - "no-div-regex": 0, - "no-else-return": [ 0, { "allowElseIf": true } ], - "no-empty-function": [ 0, { "allow": [] } ], - "no-empty-pattern": 1, - "no-eq-null": 0, - "no-eval": [ 0, { "allowIndirect": true } ], - "no-extend-native": [ 0, { "exceptions": [ ] } ], - "no-extra-bind": 0, - "no-extra-label": 0, - "no-fallthrough": [ 1, { "commentPattern": "break[\\s\\w]*omitted" } ], - "no-floating-decimal": 0, - "no-global-assign": [ 1, { "exceptions": [ "Object"] } ], - "no-implicit-coercion": - [ 0, - { "boolean": true, - "number": true, - "string": true, - "allow": [ ] } - ], - "no-implicit-globals": 0, - "no-implied-eval": 0, - "no-invalid-this": 0, - "no-iterator": 1, - "no-labels": [ 0, { "allowLoop": false, "allowSwitch": false } ], - "no-lone-blocks": 0, - "no-loop-func": 0, - "no-magic-numbers": - [ 1, - { "ignore": [ ], - "ignoreArrayIndexes": false, - "enforceConst": false, - "detectObjects": false } - ], - "no-multi-spaces": [ 0, { "ignoreEOLComments": false, "exceptions": {} } ], - "no-multi-str": 0, - "no-new": 0, - "no-new-func": 0, - "no-new-wrappers": 1, - "no-octal": 1, - "no-octal-escape": 0, - "no-param-reassign": - [ 0, - { "props": false, - "ignorePropertyModificationsFor": [ ] } - ], - "no-proto": 0, - "no-redeclare": [ 1, { "builtinGlobals": false } ], - "no-restricted-properties": 0, - "no-return-assign": [ 0, "always" ], - "no-return-await": 0, - "no-script-url": 0, - "no-self-assign": [ 1, { "props": false } ], - "no-self-compare": 0, - "no-sequences": 0, - "no-throw-literal": 0, - "no-unmodified-loop-condition": 0, - "no-unused-expressions": - [ 0, - { "allowShortCircuit": false, - "allowTernary": false, - "allowTaggedTemplates": false } - ], - "no-unused-labels": 1, - "no-useless-call": 0, - "no-useless-concat": 0, - "no-useless-escape": 1, - "no-useless-return": 0, - "no-void": 0, - "no-warning-comments": - [ 0, - { "terms": [ "todo", "fixme", "xxx" ], - "location": "start" } - ], - "no-with": 0, - "prefer-promise-reject-errors": 0, - "radix": [ 0, "always" ], - "require-await": 0, - "vars-on-top": 0, - "wrap-iife": [ 0, "outside" ], - "yoda": [ 0, "never" ], - "strict": [ 0, "safe" ], - "init-declarations": [ 0, { "ignoreForLoopInit": true } ], - "no-catch-shadow": 0, - "no-delete-var": 1, - "no-label-var": 0, - "no-restricted-globals": [ 0, "event" ], - "no-shadow": 0, - "no-shadow-restricted-names": 0, - "no-undef": [ 1, { "typeof": false } ], - "no-undef-init": 0, - "no-undefined": 0, - "no-unused-vars": [ 1, { "vars": "all", "args": "after-used" } ], - "no-use-before-define": - [ 0, - { "functions": true, "classes": true, "variables": true } - ], - "callback-return": 0, - "global-require": 0, - "handle-callback-err": [ 0, "err" ], - "no-buffer-constructor": [ 0, "err" ], - "no-mixed-requires": [ 0, { "grouping": false, "allowCall": false } ], - "no-new-require": 0, - "no-path-concat": 0, - "no-process-env": 0, - "no-process-exit": 0, - "no-restricted-modules": [ 0, { "paths": [ ] } ], - "no-sync": [ 0, { "allowAtRootLevel": false } ], - "array-bracket-newline": [ 0, { "multiline": true, "minItems": 2 } ], - "array-bracket-spacing": [ 0, "always" ], - "array-element-newline": [ 0, "always" ], - "block-spacing": [ 0, "always" ], - "brace-style": [ 0, "1tbs" ], - "camelcase": [ 0, { "properties": "always" } ], - "capitalized-comments": [ 0, "always" ], - "comma-dangle": - [ 0, - { "arrays": "never", - "objects": "never", - "imports": "never", - "exports": "never", - "functions": "ignore" } - ], - "comma-spacing": [ 0, { "before": false, "after": true } ], - "comma-style": [ 0, "last" ], - "computed-property-spacing": [ 0, "always" ], - "consistent-this": [ 0, "that" ], - "eol-last": [ 0, "always" ], - "func-call-spacing": [ 0, "never" ], - "func-name-matching": [ 0, "always" ], - "func-names": [ 0, "always" ], - "func-style": [ 0, "expression" ], - "function-paren-newline": [ 0, "multiline" ], - "id-blacklist": [ 0, "data" ], - "id-length": [ 0, { "min": 2, "properties": "always" } ], - "id-match": [ 0, "^[a-z]+([A-Z][a-z]+)*$" ], - "implicit-arrow-linebreak": [ 0, "beside" ], - "indent": [ 0, 2 ], - "jsx-quotes": 0, - "key-spacing": - [ 0, - { "beforeColon": false, "afterColon": true, "mode": "strict" } - ], - "keyword-spacing": [ 0, { "before": true, "after": true, "overrides": {} } ], - "line-comment-position": [ 0, { "position": "above" } ], - "linebreak-style": [ 0, "unix" ], - "lines-around-comment": [ 0, { "beforeBlockComment": true } ], - "lines-between-class-members": [ 0, "always" ], - "max-depth": [ 0, { "max": 4 } ], - "max-len": - [ 0, - { "code": 80, - "tabWidth": 4, - "comments": 65, - "ignoreComments": true, - "ignoreTrailingComments": true, - "ignoreUrls": true, - "ignoreStrings": true, - "ignoreTemplateLiterals": true, - "ignoreRegExpLiterals": true } - ], - "max-lines": - [ 0, - { "max": 300, "skipBlankLines": true, "skipComments": true } - ], - "max-nested-callbacks": [ 0, { "max": 10 } ], - "max-params": [ 0, { "max": 3 } ], - "max-statements": [ 0, { "max": 10 } ], - "max-statements-per-line": [ 0, { "max": 1 } ], - "multiline-comment-style": [ 0, "starred-block" ], - "multiline-ternary": [ 0, "always" ], - "new-cap": - [ 0, - { "newIsCap": true, "capIsNew": true, "properties": true } - ], - "new-parens": 0, - "newline-per-chained-call": [ 0, { "ignoreChainWithDepth": 2 } ], - "no-array-constructor": 0, - "no-bitwise": - [ 0, - { "allow": [ "~" ], "int32Hint": true } - ], - "no-continue": 0, - "no-inline-comments": 0, - "no-lonely-if": 0, - "no-mixed-operators": - [ 0, - { "groups": - [ [ "+", "-", "*", "/", "%", "**" ], - [ "&", "|", "^", "~", "<<", ">>", ">>>" ], - [ "==", "!=", "===", "!==", ">", ">=", "<", "<=" ], - [ "&&", "||" ], - [ "in", "instanceof" ] - ], - "allowSamePrecedence": true } - ], - "no-mixed-spaces-and-tabs": 1, - "no-multi-assign": 0, - "no-multiple-empty-lines": [ 0, { "max": 1 } ], - "no-negated-condition": 0, - "no-nested-ternary": 0, - "no-new-object": 0, - "no-plusplus": [ 0, { "allowForLoopAfterthoughts": true } ], - "no-restricted-syntax": 0, - "no-tabs": 0, - "no-ternary": 0, - "no-trailing-spaces": - [ 0, - { "skipBlankLines": false, "ignoreComments": false } - ], - "no-underscore-dangle": [ 0, { "allow": [ ] } ], - "no-unneeded-ternary": [ 0, { "defaultAssignment": true } ], - "no-whitespace-before-property": 0, - "nonblock-statement-body-position": [ 0, "beside" ], - "object-curly-newline": [ 0, { "multiline": true } ], - "object-curly-spacing": 0, - "one-var": [ 0, "always" ], - "one-var-declaration-per-line": [ 0, "initializations" ], - "operator-assignment": [ 0, "always" ], - "operator-linebreak": 0, - "padded-blocks": [ 0, "always" ], - "padding-line-between-statements": 0, - "quote-props": [ 0, "always" ], - "quotes": [ 0, "double" ], - "require-jsdoc": - [ 0, - { "require": - { "FunctionDeclaration": true, - "MethodDefinition": false, - "ClassDeclaration": false, - "ArrowFunctionExpression": false, - "FunctionExpression": false } } - ], - "semi": [ 0, "always" ], - "semi-spacing": [ 0, { "before": false, "after": true } ], - "semi-style": [ 0, "last" ], - "sort-keys": [ 0, "asc" ], - "sort-vars": [ 0, { "ignoreCase": true } ], - "space-before-blocks": [ 0, "always" ], - "space-before-function-paren": [ 0, "always" ], - "space-in-parens": [ 0, "never" ], - "space-infix-ops": [ 0, { "int32Hint": false } ], - "space-unary-ops": [ 0, { "words": true, "nonwords": false } ], - "spaced-comment": [ 0, "always" ], - "switch-colon-spacing": [ 0, { "after": true, "before": false } ], - "template-tag-spacing": [ 0, "never" ], - "unicode-bom": [ 0, "never" ], - "wrap-regex": 0, - "arrow-body-style": [ 0, "as-needed" ], - "arrow-parens": [ 0, "always" ], - "arrow-spacing": [ 0, { "before": true, "after": true } ], - "constructor-super": 1, - "generator-star-spacing": [ 0, { "before": true, "after": false } ], - "no-confusing-arrow": [ 0, { "allowParens": false } ], - "no-class-assign": 1, - "no-const-assign": 1, - "no-dupe-class-members": 1, - "no-duplicate-imports": [ 0, { "includeExports": false } ], - "no-new-symbol": 1, - "no-restricted-imports": - [ 0, - { "paths": [ "exampleImport1", "exampleImport2" ] } - ], - "no-this-before-super": 1, - "no-useless-computed-key": 0, - "no-useless-rename": - [ 0, - { "ignoreDestructing": false, - "ignoreImport": false, - "ignoreExport": false } - ], - "no-var": 0, - "object-shorthand": [ 0, "always" ], - "prefer-arrow-callback": - [ 0, - { "allowNamedFunction": false, "allowUnboundThis": true } - ], - "prefer-const": - [ 0, - { "destructing": "any", "ignoreReadBeforeAssign": false } - ], - "prefer-destructing": - [ 0, - [ { "array": true, "object": true }, - { "enforceForRenamedProperties": false }] - ], - "prefer-numeric-literals": 0, - "prefer-rest-params": 0, - "prefer-spread": 0, - "prefer-template": 0, - "require-yield": 1, - "rest-spread-spacing": [ 0, "never" ], - "sort-imports": - [ 0, - { "ignoreCase": false, - "ignoreMemberSort": false, - "memberSyntaxSortOrder": [ "none", "all", "multiple", "single" ] } - ], - "symbol-description": 0, - "template-curly-spacing": [ 0, "never" ], - "yield-star-spacing": [ 0, { "before": true, "after": false } ] -} diff --git a/javascript/cl/ESLintRunner/fix_esquery.js b/javascript/cl/ESLintRunner/fix_esquery.js new file mode 100644 index 0000000..14945e5 --- /dev/null +++ b/javascript/cl/ESLintRunner/fix_esquery.js @@ -0,0 +1,34 @@ +const fs = require('fs'); +const path = require('path'); + +/** + * Deletes esquery's unnecessary 'module' line from package.json + * + * With this line being present, the webpacked and minified version of ESLintRunner would throw error: + * TypeError: esquery.parse is not a function + * + * See: https://github.com/estools/esquery/issues/123 + */ +function fix_esquery() { + const esquery_path = path.resolve("node_modules", "esquery") + if (!fs.existsSync(esquery_path)) { + console.log("esquery path does not exist! Forgot to install modules with 'npm install'?"); + } + const package_json_path = path.resolve(esquery_path, 'package.json'); + const package_json = JSON.parse(fs.readFileSync(package_json_path)); + + if (package_json["module"]) { + console.log("Bad line found!") + delete package_json["module"]; + fs.writeFile(package_json_path, JSON.stringify(package_json, null, 2), (err) => { + if (err) throw err; + console.log('package.json was modified successfully!'); + }); + + } else { + console.log("Nothing to fix, 'module' was already removed from esquery's package.json!") + } + +} + +fix_esquery(); diff --git a/javascript/cl/ESLintRunner/outputFormatter.js b/javascript/cl/ESLintRunner/outputFormatter.js new file mode 100644 index 0000000..b3b5872 --- /dev/null +++ b/javascript/cl/ESLintRunner/outputFormatter.js @@ -0,0 +1,89 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +import * as os from "os"; +import {ESLINTRUNNNER_VERSION, getOption} from "./src/globals.js"; +import * as path from 'path'; +import {USE_RELATIVE_PATH} from './src/assets/constants.js'; + + +function getMessageType(message) { + if (message.fatal) { + return "fatal"; + } + return message.severity === 2 ? "error" : "warning"; +} + +function xmlEscape(s) { + const regex = /[^\u000D\u00B7\u0020-\u007E\u00A2-\u00A4]/g; + const corrected = ("" + s).replace(/[<>&"']/g, function (c) { + switch (c) { + case "<": + return " < "; + case ">": + return " > "; + case "&": + return " & "; + case "\"": + return " " "; + case "'": + return " ' "; + default: + throw new Error(`Unknown character: ${c}`); + } + }); + return ("" + corrected).replace(regex, ''); + +} + +/** + * Transforms results into Columbus-style XML + * @param resultset the results of ESLint analysis + * @returns {string} + */ +function formatter(resultset) { + let output = `${os.EOL}`; + output += `${os.EOL}`; + if (output) + resultset.forEach(function (result) { + if (getOption(USE_RELATIVE_PATH) === true) { + output += ` ${os.EOL}`; + } else { + output += ` ${os.EOL}`; + } + result.messages.forEach(function (message) { + output += ` ${os.EOL}`; + }); + output += ` ${os.EOL}`; + }); + output += ``; + output += `${os.EOL}`; + return output; +} + +export { + formatter +} \ No newline at end of file diff --git a/javascript/cl/ESLintRunner/package-lock.json b/javascript/cl/ESLintRunner/package-lock.json new file mode 100644 index 0000000..0b564d3 --- /dev/null +++ b/javascript/cl/ESLintRunner/package-lock.json @@ -0,0 +1,11473 @@ +{ + "name": "ESLintRunner", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "ESLintRunner", + "version": "1.0.0", + "dependencies": { + "@rollup/plugin-commonjs": "21.0.0", + "@rollup/plugin-eslint": "^8.0.1", + "@rollup/plugin-json": "^4.1.0", + "@rollup/plugin-node-resolve": "^13.0.5", + "@typescript-eslint/eslint-plugin": "^4.33.0", + "@typescript-eslint/eslint-plugin-tslint": "^4.33.0", + "@typescript-eslint/parser": "^4.33.0", + "@typescript-eslint/typescript-estree": "^4.33.0", + "clean-webpack-plugin": "^4.0.0", + "command-line-args": "5.2.0", + "command-line-usage": "6.1.1", + "copy-webpack-plugin": "^9.0.1", + "eslint": "^7.32.0", + "eslint-config-recommended": "^2.0.0", + "node-loader": "2.0.0", + "rollup": "^2.58.0", + "rollup-plugin-copy": "^3.4.0", + "typescript": "^4.4.3", + "xml2js": "0.4.23" + }, + "devDependencies": { + "webpack": "^5.45.1", + "webpack-cli": "^4.7.2", + "webpack-merge": "^5.8.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/@babel/generator": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.44.tgz", + "integrity": "sha512-5xVb7hlhjGcdkKpMXgicAVgx8syK5VJz193k0i/0sLP6DzE6lRrU1K3B/rFefgdo9LPGMAOOOAWW4jycj07ShQ==", + "dependencies": { + "@babel/types": "7.0.0-beta.44", + "jsesc": "^2.5.1", + "lodash": "^4.2.0", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + } + }, + "node_modules/@babel/generator/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz", + "integrity": "sha512-MHRG2qZMKMFaBavX0LWpfZ2e+hLloT++N7rfM3DYOMUOGCD8cVjqZpwiL8a0bOX3IYcQev1ruciT0gdFFRTxzg==", + "dependencies": { + "@babel/helper-get-function-arity": "7.0.0-beta.44", + "@babel/template": "7.0.0-beta.44", + "@babel/types": "7.0.0-beta.44" + } + }, + "node_modules/@babel/helper-get-function-arity": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz", + "integrity": "sha512-w0YjWVwrM2HwP6/H3sEgrSQdkCaxppqFeJtAnB23pRiJB5E/O9Yp7JAAeWBl+gGEgmBFinnTyOv2RN7rcSmMiw==", + "dependencies": { + "@babel/types": "7.0.0-beta.44" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz", + "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", + "dependencies": { + "@babel/types": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables/node_modules/@babel/types": { + "version": "7.15.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz", + "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.14.9", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz", + "integrity": "sha512-aQ7QowtkgKKzPGf0j6u77kBMdUFVBKNHw2p/3HX/POt5/oz8ec5cs0GwlgM8Hz7ui5EwJnzyfRmkNF1Nx1N7aA==", + "dependencies": { + "@babel/types": "7.0.0-beta.44" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz", + "integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.44.tgz", + "integrity": "sha512-w750Sloq0UNifLx1rUqwfbnC6uSUk0mfwwgGRfdLiaUzfAOiH0tHJE6ILQIUi3KYkjiCDTskoIsnfqZvWLBDng==", + "dependencies": { + "@babel/code-frame": "7.0.0-beta.44", + "@babel/types": "7.0.0-beta.44", + "babylon": "7.0.0-beta.44", + "lodash": "^4.2.0" + } + }, + "node_modules/@babel/template/node_modules/@babel/code-frame": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz", + "integrity": "sha512-cuAuTTIQ9RqcFRJ/Y8PvTh+paepNcaGxwQwjIDRWPXmzzyAeCO4KqS9ikMvq0MCbRk6GlYKwfzStrcP3/jSL8g==", + "dependencies": { + "@babel/highlight": "7.0.0-beta.44" + } + }, + "node_modules/@babel/template/node_modules/@babel/highlight": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.44.tgz", + "integrity": "sha512-Il19yJvy7vMFm8AVAh6OZzaFoAd0hbkeMZiX3P5HGD+z7dyI7RzndHB0dg6Urh/VAFfHtpOIzDUSxmY6coyZWQ==", + "dependencies": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^3.0.0" + } + }, + "node_modules/@babel/template/node_modules/js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + }, + "node_modules/@babel/traverse": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.44.tgz", + "integrity": "sha512-UHuDz8ukQkJCDASKHf+oDt3FVUzFd+QYfuBIsiNu/4+/ix6pP/C+uQZJ6K1oEfbCMv/IKWbgDEh7fcsnIE5AtA==", + "dependencies": { + "@babel/code-frame": "7.0.0-beta.44", + "@babel/generator": "7.0.0-beta.44", + "@babel/helper-function-name": "7.0.0-beta.44", + "@babel/helper-split-export-declaration": "7.0.0-beta.44", + "@babel/types": "7.0.0-beta.44", + "babylon": "7.0.0-beta.44", + "debug": "^3.1.0", + "globals": "^11.1.0", + "invariant": "^2.2.0", + "lodash": "^4.2.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/code-frame": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz", + "integrity": "sha512-cuAuTTIQ9RqcFRJ/Y8PvTh+paepNcaGxwQwjIDRWPXmzzyAeCO4KqS9ikMvq0MCbRk6GlYKwfzStrcP3/jSL8g==", + "dependencies": { + "@babel/highlight": "7.0.0-beta.44" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/highlight": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.44.tgz", + "integrity": "sha512-Il19yJvy7vMFm8AVAh6OZzaFoAd0hbkeMZiX3P5HGD+z7dyI7RzndHB0dg6Urh/VAFfHtpOIzDUSxmY6coyZWQ==", + "dependencies": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^3.0.0" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/traverse/node_modules/js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + }, + "node_modules/@babel/types": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.44.tgz", + "integrity": "sha512-5eTV4WRmqbaFM3v9gHAIljEQJU4Ssc6fxL61JN+Oe2ga/BwyjzjamwkCVVAQjHGuAX8i0BWo42dshL8eO5KfLQ==", + "dependencies": { + "esutils": "^2.0.2", + "lodash": "^4.2.0", + "to-fast-properties": "^2.0.0" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.5.tgz", + "integrity": "sha512-6nFkfkmSeV/rqSaS4oWHgmpnYw194f6hmWF5is6b0J1naJZoiD0NTc9AiUwPHvWsowkjuHErCZT1wa0jg+BLIA==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", + "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rollup/plugin-commonjs": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-21.0.0.tgz", + "integrity": "sha512-XDQimjHl0kNotAV5lLo34XoygaI0teqiKGJ100B3iCU8+15YscJPeqk2KqkqD3NIe1H8ZTUo5lYjUFZyEgASTw==", + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "commondir": "^1.0.1", + "estree-walker": "^2.0.1", + "glob": "^7.1.6", + "is-reference": "^1.2.1", + "magic-string": "^0.25.7", + "resolve": "^1.17.0" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^2.38.3" + } + }, + "node_modules/@rollup/plugin-eslint": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-eslint/-/plugin-eslint-8.0.1.tgz", + "integrity": "sha512-rTMAY4tKGBdbkHHQDaVhXNJg9tRmW7ihRAg7NQHiPUv13NFYBygIr+OYgpVNwSnGOH146BgCITSBAoMxMQGPTQ==", + "dependencies": { + "@rollup/pluginutils": "^4.0.0", + "eslint": "^7.12.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/plugin-eslint/node_modules/@rollup/pluginutils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.1.1.tgz", + "integrity": "sha512-clDjivHqWGXi7u+0d2r2sBi4Ie6VLEAzWMIkvJLnDmxoOhBYOTfzGbOQBA32THHm11/LiJbd01tJUpJsbshSWQ==", + "dependencies": { + "estree-walker": "^2.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/@rollup/plugin-json": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", + "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", + "dependencies": { + "@rollup/pluginutils": "^3.0.8" + }, + "peerDependencies": { + "rollup": "^1.20.0 || ^2.0.0" + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.0.5.tgz", + "integrity": "sha512-mVaw6uxtvuGx/XCI4qBQXsDZJUfyx5vp39iE0J/7Hd6wDhEbjHr6aES7Nr9yWbuE0BY+oKp6N7Bq6jX5NCGNmQ==", + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "rollup": "^2.42.0" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" + }, + "node_modules/@types/eslint": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.0.tgz", + "integrity": "sha512-07XlgzX0YJUn4iG1ocY4IX9DzKSmMGUs6ESKlxWhZRaa0fatIWaHWUVapcuGa8r5HFnTqzj+4OCjd5f7EZ/i/A==", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.1.tgz", + "integrity": "sha512-SCFeogqiptms4Fg29WpOTk5nHIzfpKCemSN63ksBQYKTcXoJEmJagV+DhVmbapZzY4/5YaOV1nZwrsU79fFm1g==", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" + }, + "node_modules/@types/fs-extra": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.2.tgz", + "integrity": "sha512-SvSrYXfWSc7R4eqnOzbQF4TZmfpNSM9FrSWLU3EUnWBuyZqNBOrv1B1JA3byUDPUl9z4Ab3jeZG2eDdySlgNMg==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==", + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", + "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" + }, + "node_modules/@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==" + }, + "node_modules/@types/node": { + "version": "16.10.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.3.tgz", + "integrity": "sha512-ho3Ruq+fFnBrZhUYI46n/bV2GjwzSkwuT4dTf0GkuNFmnb8nq4ny2z9JEVemFi6bdEJanHLlYfy9c6FN9B9McQ==" + }, + "node_modules/@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz", + "integrity": "sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==", + "dependencies": { + "@typescript-eslint/experimental-utils": "4.33.0", + "@typescript-eslint/scope-manager": "4.33.0", + "debug": "^4.3.1", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.1.8", + "regexpp": "^3.1.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^4.0.0", + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin-tslint": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin-tslint/-/eslint-plugin-tslint-4.33.0.tgz", + "integrity": "sha512-o3ujMErtZJPgiNRETRJefo1bFNrloocOa5dMU49OW/G+Rq92IbXTY6FSF5MOwrdQK1X+VBEcA8y6PhUPWGlYqA==", + "dependencies": { + "@typescript-eslint/experimental-utils": "4.33.0", + "lodash": "^4.17.21" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "peerDependencies": { + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0", + "tslint": "^5.0.0 || ^6.0.0", + "typescript": "*" + } + }, + "node_modules/@typescript-eslint/experimental-utils": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz", + "integrity": "sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==", + "dependencies": { + "@types/json-schema": "^7.0.7", + "@typescript-eslint/scope-manager": "4.33.0", + "@typescript-eslint/types": "4.33.0", + "@typescript-eslint/typescript-estree": "4.33.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz", + "integrity": "sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==", + "dependencies": { + "@typescript-eslint/scope-manager": "4.33.0", + "@typescript-eslint/types": "4.33.0", + "@typescript-eslint/typescript-estree": "4.33.0", + "debug": "^4.3.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz", + "integrity": "sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==", + "dependencies": { + "@typescript-eslint/types": "4.33.0", + "@typescript-eslint/visitor-keys": "4.33.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz", + "integrity": "sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==", + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz", + "integrity": "sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==", + "dependencies": { + "@typescript-eslint/types": "4.33.0", + "@typescript-eslint/visitor-keys": "4.33.0", + "debug": "^4.3.1", + "globby": "^11.0.3", + "is-glob": "^4.0.1", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz", + "integrity": "sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==", + "dependencies": { + "@typescript-eslint/types": "4.33.0", + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.0.tgz", + "integrity": "sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg==", + "dev": true, + "peerDependencies": { + "webpack": "4.x.x || 5.x.x", + "webpack-cli": "4.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.0.tgz", + "integrity": "sha512-F6b+Man0rwE4n0409FyAJHStYA5OIZERxmnUfLVwv0mc0V1wLad3V7jqRlMkgKBeAq07jUvglacNaa6g9lOpuw==", + "dev": true, + "dependencies": { + "envinfo": "^7.7.3" + }, + "peerDependencies": { + "webpack-cli": "4.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.0.tgz", + "integrity": "sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA==", + "dev": true, + "peerDependencies": { + "webpack-cli": "4.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/array-includes": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", + "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", + "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz", + "integrity": "sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA==", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dependencies": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + } + }, + "node_modules/babel-code-frame/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-code-frame/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-code-frame/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-code-frame/node_modules/js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + }, + "node_modules/babel-code-frame/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-code-frame/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/babel-eslint": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.6.tgz", + "integrity": "sha512-aCdHjhzcILdP8c9lej7hvXKvQieyRt20SF102SIGyY4cUIiw6UaAtK4j2o3dXX74jEmy0TJ0CEhv4fTIM3SzcA==", + "deprecated": "babel-eslint is now @babel/eslint-parser. This package will no longer receive updates.", + "dependencies": { + "@babel/code-frame": "7.0.0-beta.44", + "@babel/traverse": "7.0.0-beta.44", + "@babel/types": "7.0.0-beta.44", + "babylon": "7.0.0-beta.44", + "eslint-scope": "3.7.1", + "eslint-visitor-keys": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/babel-eslint/node_modules/@babel/code-frame": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz", + "integrity": "sha512-cuAuTTIQ9RqcFRJ/Y8PvTh+paepNcaGxwQwjIDRWPXmzzyAeCO4KqS9ikMvq0MCbRk6GlYKwfzStrcP3/jSL8g==", + "dependencies": { + "@babel/highlight": "7.0.0-beta.44" + } + }, + "node_modules/babel-eslint/node_modules/@babel/highlight": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.44.tgz", + "integrity": "sha512-Il19yJvy7vMFm8AVAh6OZzaFoAd0hbkeMZiX3P5HGD+z7dyI7RzndHB0dg6Urh/VAFfHtpOIzDUSxmY6coyZWQ==", + "dependencies": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^3.0.0" + } + }, + "node_modules/babel-eslint/node_modules/eslint-scope": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", + "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", + "dependencies": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/babel-eslint/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/babel-eslint/node_modules/js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + }, + "node_modules/babylon": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz", + "integrity": "sha512-5Hlm13BJVAioCHpImtFqNOF2H3ieTOHd0fmFGMxOJ9jgeFqeAwsv3u5P5cR7CSeFrkgHsT19DgFJkHV0/Mcd8g==", + "bin": { + "babylon": "bin/babylon.js" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "engines": { + "node": "*" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.3.tgz", + "integrity": "sha512-59IqHJV5VGdcJZ+GZ2hU5n4Kv3YiASzW6Xk5g9tf5a/MAzGeFwgGWU39fVzNIOVcgB3+Gp+kiQu0HEfTVU/3VQ==", + "dependencies": { + "caniuse-lite": "^1.0.30001264", + "electron-to-chromium": "^1.3.857", + "escalade": "^3.1.1", + "node-releases": "^1.1.77", + "picocolors": "^0.2.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/builtin-modules": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", + "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dependencies": { + "callsites": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/caller-path/node_modules/callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001265", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001265.tgz", + "integrity": "sha512-YzBnspggWV5hep1m9Z6sZVLOt7vrju8xWooFAgN6BA5qvy98qPAPb7vNUzypFaoh2pb3vlfzbDO8tB57UPGbtw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=" + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "deprecated": "CircularJSON is in maintenance only, flatted is its successor." + }, + "node_modules/clean-webpack-plugin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-4.0.0.tgz", + "integrity": "sha512-WuWE1nyTNAyW5T7oNyys2EN0cfP2fdRxhxnIQWiAp0bMabPdHhoGxM8A6YL2GhqwgrPnnaemVE7nv5XJ2Fhh2w==", + "dependencies": { + "del": "^4.1.1" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "webpack": ">=4.0.0 <6.0.0" + } + }, + "node_modules/cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dependencies": { + "restore-cursor": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==" + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clone-deep/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "node_modules/colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==" + }, + "node_modules/command-line-args": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.0.tgz", + "integrity": "sha512-4zqtU1hYsSJzcJBOcNZIbW5Fbk9BkjCp1pZVhQKoRaWL5J7N4XphDLwo8aWwdQpTugxwu+jf9u2ZhkXiqp5Z6A==", + "dependencies": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/command-line-usage": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.1.tgz", + "integrity": "sha512-F59pEuAR9o1SF/bD0dQBDluhpT4jJQNWUHEuVBqpDmCUo6gPjCi+m9fCWnWZVR/oG6cMTUms4h+3NPl74wGXvA==", + "dependencies": { + "array-back": "^4.0.1", + "chalk": "^2.4.2", + "table-layout": "^1.0.1", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/command-line-usage/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/command-line-usage/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-9.0.1.tgz", + "integrity": "sha512-14gHKKdYIxF84jCEgPgYXCPpldbwpxxLbCmA7LReY7gvbaT555DgeBWBgBZM116tv/fO6RRJrsivBqRyRlukhw==", + "dependencies": { + "fast-glob": "^3.2.5", + "glob-parent": "^6.0.0", + "globby": "^11.0.3", + "normalize-path": "^3.0.0", + "p-limit": "^3.1.0", + "schema-utils": "^3.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "dependencies": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/del/node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dependencies": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/globby/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "peer": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.3.862", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.862.tgz", + "integrity": "sha512-o+FMbCD+hAUJ9S8bfz/FaqA0gE8OpCCm58KhhGogOEqiA1BLFSoVYLi+tW+S/ZavnqBn++n0XZm7HQiBVPs8Jg==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz", + "integrity": "sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA==", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==" + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "dependencies": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-esnext": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-esnext/-/eslint-config-esnext-2.0.0.tgz", + "integrity": "sha1-PWyeh+0KDucvJ5cTjrC86yCJfKI=", + "dependencies": { + "babel-eslint": "^8.0.2", + "eslint": "^4.0.0", + "eslint-plugin-babel": "^4.1.2", + "eslint-plugin-import": "^2.8.0" + }, + "peerDependencies": { + "babel-eslint": "^8.0.2", + "eslint": "^4.0.0", + "eslint-plugin-babel": "^4.1.2", + "eslint-plugin-import": "^2.8.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dependencies": { + "acorn": "^3.0.4" + } + }, + "node_modules/eslint-config-esnext/node_modules/acorn-jsx/node_modules/acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dependencies": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/ajv-keywords": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", + "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", + "peerDependencies": { + "ajv": ">=4.10.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dependencies": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "node_modules/eslint-config-esnext/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/eslint": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.4.1.tgz", + "integrity": "sha1-mc1+r8/8ov+Zpcj18qR01jZLS9M=", + "dependencies": { + "ajv": "^5.2.0", + "babel-code-frame": "^6.22.0", + "chalk": "^1.1.3", + "concat-stream": "^1.6.0", + "cross-spawn": "^5.1.0", + "debug": "^2.6.8", + "doctrine": "^2.0.0", + "eslint-scope": "^3.7.1", + "espree": "^3.5.0", + "esquery": "^1.0.0", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^9.17.0", + "ignore": "^3.3.3", + "imurmurhash": "^0.1.4", + "inquirer": "^3.0.6", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.9.1", + "json-stable-stringify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^4.0.0", + "progress": "^2.0.0", + "require-uncached": "^1.0.3", + "semver": "^5.3.0", + "strip-json-comments": "~2.0.1", + "table": "^4.0.1", + "text-table": "~0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/eslint-plugin-babel": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-babel/-/eslint-plugin-babel-4.1.2.tgz", + "integrity": "sha1-eSAqDjV1fdkngJGbIzbx+i/lPB4=", + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": ">=3.0.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/eslint-plugin-import": { + "version": "2.24.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.24.2.tgz", + "integrity": "sha512-hNVtyhiEtZmpsabL4neEj+6M5DCLgpYyG9nzJY8lZQeQXEn5UPW1DpUdsMHMXsq98dbNm7nt1w9ZMSVpfJdi8Q==", + "dependencies": { + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.6.2", + "find-up": "^2.0.0", + "has": "^1.0.3", + "is-core-module": "^2.6.0", + "minimatch": "^3.0.4", + "object.values": "^1.1.4", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.11.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", + "dependencies": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "dependencies": { + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + }, + "node_modules/eslint-config-esnext/node_modules/file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dependencies": { + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/flat-cache": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", + "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "dependencies": { + "circular-json": "^0.3.1", + "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", + "write": "^0.2.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==" + }, + "node_modules/eslint-config-esnext/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + }, + "node_modules/eslint-config-esnext/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/eslint-config-esnext/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/eslint-config-esnext/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/eslint-config-esnext/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/eslint-config-esnext/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/string-width": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.0.0.tgz", + "integrity": "sha1-Y1xUNsxypuDDh87KJ41OLuxSaH4=", + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/table": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.1.tgz", + "integrity": "sha1-qBFsEz+sLGH0pCCrbN9cTWHw5DU=", + "dependencies": { + "ajv": "^4.7.0", + "ajv-keywords": "^1.0.0", + "chalk": "^1.1.1", + "lodash": "^4.0.0", + "slice-ansi": "0.0.4", + "string-width": "^2.0.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/table/node_modules/ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "dependencies": { + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" + } + }, + "node_modules/eslint-config-esnext/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/eslint-config-esnext/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, + "node_modules/eslint-config-recommended": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-recommended/-/eslint-config-recommended-2.0.0.tgz", + "integrity": "sha1-I1gX/da6j7A8/eOZWunm64+Y51Q=", + "dependencies": { + "babel-eslint": "^8.0.2", + "eslint": "^4.0.0", + "eslint-config-esnext": "^2.0.0", + "eslint-plugin-babel": "^4.1.2", + "eslint-plugin-import": "^2.8.0", + "eslint-plugin-react": "^7.5.0", + "eslint-plugin-react-native": "^3.2.0" + }, + "peerDependencies": { + "babel-eslint": "^8.0.2", + "eslint": "^4.0.0", + "eslint-config-esnext": "^2.0.0", + "eslint-plugin-babel": "^4.1.2", + "eslint-plugin-import": "^2.8.0", + "eslint-plugin-react": "^7.5.0", + "eslint-plugin-react-native": "^3.2.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/@babel/code-frame": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", + "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", + "dependencies": { + "@babel/highlight": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/@babel/generator": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz", + "integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==", + "dependencies": { + "@babel/types": "^7.15.6", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/@babel/helper-function-name": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz", + "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", + "dependencies": { + "@babel/helper-get-function-arity": "^7.15.4", + "@babel/template": "^7.15.4", + "@babel/types": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/@babel/helper-get-function-arity": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz", + "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", + "dependencies": { + "@babel/types": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/@babel/helper-split-export-declaration": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz", + "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", + "dependencies": { + "@babel/types": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/@babel/template": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz", + "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", + "dependencies": { + "@babel/code-frame": "^7.14.5", + "@babel/parser": "^7.15.4", + "@babel/types": "^7.15.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/@babel/traverse": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz", + "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", + "dependencies": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.15.4", + "@babel/helper-function-name": "^7.15.4", + "@babel/helper-hoist-variables": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4", + "@babel/parser": "^7.15.4", + "@babel/types": "^7.15.4", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/@babel/traverse/node_modules/debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint-config-recommended/node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/@babel/traverse/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/eslint-config-recommended/node_modules/@babel/types": { + "version": "7.15.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz", + "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.14.9", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dependencies": { + "acorn": "^3.0.4" + } + }, + "node_modules/eslint-config-recommended/node_modules/acorn-jsx/node_modules/acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dependencies": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/ajv-keywords": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", + "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", + "peerDependencies": { + "ajv": ">=4.10.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dependencies": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "node_modules/eslint-config-recommended/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/eslint": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.4.1.tgz", + "integrity": "sha1-mc1+r8/8ov+Zpcj18qR01jZLS9M=", + "dependencies": { + "ajv": "^5.2.0", + "babel-code-frame": "^6.22.0", + "chalk": "^1.1.3", + "concat-stream": "^1.6.0", + "cross-spawn": "^5.1.0", + "debug": "^2.6.8", + "doctrine": "^2.0.0", + "eslint-scope": "^3.7.1", + "espree": "^3.5.0", + "esquery": "^1.0.0", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^9.17.0", + "ignore": "^3.3.3", + "imurmurhash": "^0.1.4", + "inquirer": "^3.0.6", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.9.1", + "json-stable-stringify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^4.0.0", + "progress": "^2.0.0", + "require-uncached": "^1.0.3", + "semver": "^5.3.0", + "strip-json-comments": "~2.0.1", + "table": "^4.0.1", + "text-table": "~0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/eslint-plugin-babel": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-babel/-/eslint-plugin-babel-4.1.2.tgz", + "integrity": "sha1-eSAqDjV1fdkngJGbIzbx+i/lPB4=", + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": ">=3.0.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/eslint-plugin-import": { + "version": "2.24.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.24.2.tgz", + "integrity": "sha512-hNVtyhiEtZmpsabL4neEj+6M5DCLgpYyG9nzJY8lZQeQXEn5UPW1DpUdsMHMXsq98dbNm7nt1w9ZMSVpfJdi8Q==", + "dependencies": { + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.6.2", + "find-up": "^2.0.0", + "has": "^1.0.3", + "is-core-module": "^2.6.0", + "minimatch": "^3.0.4", + "object.values": "^1.1.4", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.11.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/eslint-plugin-react": { + "version": "7.26.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.26.1.tgz", + "integrity": "sha512-Lug0+NOFXeOE+ORZ5pbsh6mSKjBKXDXItUD2sQoT+5Yl0eoT82DqnXeTMfUare4QVCn9QwXbfzO/dBLjLXwVjQ==", + "dependencies": { + "array-includes": "^3.1.3", + "array.prototype.flatmap": "^1.2.4", + "doctrine": "^2.1.0", + "estraverse": "^5.2.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.0.4", + "object.entries": "^1.1.4", + "object.fromentries": "^2.0.4", + "object.hasown": "^1.0.0", + "object.values": "^1.1.4", + "prop-types": "^15.7.2", + "resolve": "^2.0.0-next.3", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.5" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7" + } + }, + "node_modules/eslint-config-recommended/node_modules/eslint-plugin-react-native": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-native/-/eslint-plugin-react-native-3.11.0.tgz", + "integrity": "sha512-7F3OTwrtQPfPFd+VygqKA2VZ0f2fz0M4gJmry/TRE18JBb94/OtMxwbL7Oqwu7FGyrdeIOWnXQbBAveMcSTZIA==", + "dependencies": { + "@babel/traverse": "^7.7.4", + "eslint-plugin-react-native-globals": "^0.1.1" + }, + "peerDependencies": { + "eslint": "^3.17.0 || ^4 || ^5 || ^6 || ^7" + } + }, + "node_modules/eslint-config-recommended/node_modules/eslint-plugin-react/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", + "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", + "dependencies": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-config-recommended/node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-config-recommended/node_modules/eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", + "dependencies": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "dependencies": { + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + }, + "node_modules/eslint-config-recommended/node_modules/file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dependencies": { + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/flat-cache": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", + "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "dependencies": { + "circular-json": "^0.3.1", + "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", + "write": "^0.2.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==" + }, + "node_modules/eslint-config-recommended/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + }, + "node_modules/eslint-config-recommended/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/eslint-config-recommended/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/eslint-config-recommended/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/eslint-config-recommended/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/eslint-config-recommended/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/string-width": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.0.0.tgz", + "integrity": "sha1-Y1xUNsxypuDDh87KJ41OLuxSaH4=", + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/table": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.1.tgz", + "integrity": "sha1-qBFsEz+sLGH0pCCrbN9cTWHw5DU=", + "dependencies": { + "ajv": "^4.7.0", + "ajv-keywords": "^1.0.0", + "chalk": "^1.1.1", + "lodash": "^4.0.0", + "slice-ansi": "0.0.4", + "string-width": "^2.0.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/table/node_modules/ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "dependencies": { + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" + } + }, + "node_modules/eslint-config-recommended/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/eslint-config-recommended/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "dependencies": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.2.tgz", + "integrity": "sha512-QG8pcgThYOuqxupd06oYTZoNOGaUdTY1PqK+oS6ElF6vs4pBdk/aYxFVQQXzcrAqp9m7cl7lb2ubazX+g16k2Q==", + "dependencies": { + "debug": "^3.2.7", + "pkg-dir": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dependencies": { + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-react-native-globals": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz", + "integrity": "sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g==" + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint/node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/external-editor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", + "dependencies": { + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-glob": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", + "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", + "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "dependencies": { + "array-back": "^3.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flatted": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", + "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==" + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" + }, + "node_modules/get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "node_modules/globals": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", + "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", + "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", + "integrity": "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "dependencies": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.4", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rx-lite": "^4.0.8", + "rx-lite-aggregates": "^4.0.8", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" + } + }, + "node_modules/inquirer/node_modules/ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "engines": { + "node": ">=4" + } + }, + "node_modules/inquirer/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "engines": { + "node": ">=4" + } + }, + "node_modules/inquirer/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/inquirer/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dependencies": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.7.0.tgz", + "integrity": "sha512-ByY+tjCciCr+9nLryBYcSD50EOGWt95c7tIsKTG1J2ixKKXPvF7Ej3AVd+UfDydAJom3biBGDBALaO79ktwgEQ==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=" + }, + "node_modules/is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", + "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "dependencies": { + "is-path-inside": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "dependencies": { + "path-is-inside": "^1.0.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-plain-object": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", + "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==" + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", + "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", + "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", + "dependencies": { + "call-bind": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-worker": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.2.5.tgz", + "integrity": "sha512-HTjEPZtcNKZ4LnhSp02NEH4vE+5OpJ0EsOWYvGQpHgUMLngydESAAMH5Wd/asPf29+XUDQZszxpLg1BkIIA2aw==", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dependencies": { + "jsonify": "~0.0.0" + } + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + }, + "node_modules/json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "engines": { + "node": "*" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz", + "integrity": "sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==", + "dependencies": { + "array-includes": "^3.1.3", + "object.assign": "^4.1.2" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "engines": { + "node": ">=4" + } + }, + "node_modules/loader-runner": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", + "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/magic-string": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", + "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "dependencies": { + "sourcemap-codec": "^1.4.4" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.50.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", + "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.33", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", + "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", + "dependencies": { + "mime-db": "1.50.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node_modules/node-loader": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/node-loader/-/node-loader-2.0.0.tgz", + "integrity": "sha512-I5VN34NO4/5UYJaUBtkrODPWxbobrE4hgDqPrjB25yPkonFhCmZ146vTH+Zg417E9Iwoh1l/MbRs1apc5J295Q==", + "dependencies": { + "loader-utils": "^2.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/node-releases": { + "version": "1.1.77", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz", + "integrity": "sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ==" + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.hasown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.0.tgz", + "integrity": "sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg==", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "engines": { + "node": ">=4" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" + }, + "node_modules/picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "engines": { + "node": ">=6" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dependencies": { + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "engines": { + "node": ">=4" + } + }, + "node_modules/pluralize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-4.0.0.tgz", + "integrity": "sha1-WbcIwcAZCi9pLxx2GMRGsFL9F2I=" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dependencies": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "engines": { + "node": ">=4" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "dev": true, + "dependencies": { + "resolve": "^1.9.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", + "engines": { + "node": ">=6" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", + "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dependencies": { + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-uncached/node_modules/resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dependencies": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dependencies": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor/node_modules/mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dependencies": { + "mimic-fn": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/rollup": { + "version": "2.58.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.58.0.tgz", + "integrity": "sha512-NOXpusKnaRpbS7ZVSzcEXqxcLDOagN6iFS8p45RkoiMqPHDLwJm758UF05KlMoCRbLBTZsPOIa887gZJ1AiXvw==", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-copy": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.4.0.tgz", + "integrity": "sha512-rGUmYYsYsceRJRqLVlE9FivJMxJ7X6jDlP79fmFkL8sJs7VVMSVyA2yfyL+PGyO/vJs4A87hwhgVfz61njI+uQ==", + "dependencies": { + "@types/fs-extra": "^8.0.1", + "colorette": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "10.0.1", + "is-plain-object": "^3.0.0" + }, + "engines": { + "node": ">=8.3" + } + }, + "node_modules/rollup-plugin-copy/node_modules/globby": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", + "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", + "dependencies": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rx-lite": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=" + }, + "node_modules/rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "dependencies": { + "rx-lite": "*" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", + "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.20", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", + "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz", + "integrity": "sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==" + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz", + "integrity": "sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.3.1", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/table": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.2.tgz", + "integrity": "sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g==", + "dependencies": { + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table-layout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", + "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", + "dependencies": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/table-layout/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/table-layout/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.6.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", + "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.9.0.tgz", + "integrity": "sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ==", + "dependencies": { + "commander": "^2.20.0", + "source-map": "~0.7.2", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.2.4.tgz", + "integrity": "sha512-E2CkNMN+1cho04YpdANyRrn8CyN4yMy+WdFKZIySFZrGXZxJwJP6PMNGGc/Mcr6qygQHUUqRxnAPmi0M9f00XA==", + "dependencies": { + "jest-worker": "^27.0.6", + "p-limit": "^3.1.0", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1", + "terser": "^5.7.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz", + "integrity": "sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/tslint": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", + "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", + "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.3", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.13.0", + "tsutils": "^2.29.0" + }, + "bin": { + "tslint": "bin/tslint" + }, + "engines": { + "node": ">=4.8.0" + }, + "peerDependencies": { + "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 4.0.0-dev" + } + }, + "node_modules/tslint/node_modules/builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tslint/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "peer": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/tslint/node_modules/tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "peer": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "peerDependencies": { + "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" + } + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "node_modules/typescript": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz", + "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dependencies": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==" + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/watchpack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz", + "integrity": "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack": { + "version": "5.58.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.58.1.tgz", + "integrity": "sha512-4Z/dmbTU+VmkCb2XNgW7wkE5TfEcSooclprn/UEuVeAkwHhn07OcgUsyaKHGtCY/VobjnsYBlyhKeMLiSoOqPg==", + "dependencies": { + "@types/eslint-scope": "^3.7.0", + "@types/estree": "^0.0.50", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.4.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.8.3", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.4", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.2.0", + "webpack-sources": "^3.2.0" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.0.tgz", + "integrity": "sha512-n/jZZBMzVEl4PYIBs+auy2WI0WTQ74EnJDiyD98O2JZY6IVIHJNitkYp/uTXOviIOMfgzrNvC9foKv/8o8KSZw==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.1.0", + "@webpack-cli/info": "^1.4.0", + "@webpack-cli/serve": "^1.6.0", + "colorette": "^2.0.14", + "commander": "^7.0.0", + "execa": "^5.0.0", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "v8-compile-cache": "^2.2.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "webpack": "4.x.x || 5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "@webpack-cli/migrate": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/colorette": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", + "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", + "dev": true + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.1.tgz", + "integrity": "sha512-t6BMVLQ0AkjBOoRTZgqrWm7xbXMBzD+XDq2EZ96+vMfn3qKgsvdXZhbPZ4ElUOpdv4u+iiGe+w3+J75iy/bYGA==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/@types/estree": { + "version": "0.0.50", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", + "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==" + }, + "node_modules/webpack/node_modules/acorn": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", + "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/webpack/node_modules/acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrapjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", + "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", + "dependencies": { + "reduce-flatten": "^2.0.0", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/wordwrapjs/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dependencies": { + "mkdirp": "^0.5.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/generator": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.44.tgz", + "integrity": "sha512-5xVb7hlhjGcdkKpMXgicAVgx8syK5VJz193k0i/0sLP6DzE6lRrU1K3B/rFefgdo9LPGMAOOOAWW4jycj07ShQ==", + "requires": { + "@babel/types": "7.0.0-beta.44", + "jsesc": "^2.5.1", + "lodash": "^4.2.0", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "@babel/helper-function-name": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz", + "integrity": "sha512-MHRG2qZMKMFaBavX0LWpfZ2e+hLloT++N7rfM3DYOMUOGCD8cVjqZpwiL8a0bOX3IYcQev1ruciT0gdFFRTxzg==", + "requires": { + "@babel/helper-get-function-arity": "7.0.0-beta.44", + "@babel/template": "7.0.0-beta.44", + "@babel/types": "7.0.0-beta.44" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz", + "integrity": "sha512-w0YjWVwrM2HwP6/H3sEgrSQdkCaxppqFeJtAnB23pRiJB5E/O9Yp7JAAeWBl+gGEgmBFinnTyOv2RN7rcSmMiw==", + "requires": { + "@babel/types": "7.0.0-beta.44" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz", + "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", + "requires": { + "@babel/types": "^7.15.4" + }, + "dependencies": { + "@babel/types": { + "version": "7.15.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz", + "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", + "requires": { + "@babel/helper-validator-identifier": "^7.14.9", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz", + "integrity": "sha512-aQ7QowtkgKKzPGf0j6u77kBMdUFVBKNHw2p/3HX/POt5/oz8ec5cs0GwlgM8Hz7ui5EwJnzyfRmkNF1Nx1N7aA==", + "requires": { + "@babel/types": "7.0.0-beta.44" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==" + }, + "@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "requires": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz", + "integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==" + }, + "@babel/template": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.44.tgz", + "integrity": "sha512-w750Sloq0UNifLx1rUqwfbnC6uSUk0mfwwgGRfdLiaUzfAOiH0tHJE6ILQIUi3KYkjiCDTskoIsnfqZvWLBDng==", + "requires": { + "@babel/code-frame": "7.0.0-beta.44", + "@babel/types": "7.0.0-beta.44", + "babylon": "7.0.0-beta.44", + "lodash": "^4.2.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz", + "integrity": "sha512-cuAuTTIQ9RqcFRJ/Y8PvTh+paepNcaGxwQwjIDRWPXmzzyAeCO4KqS9ikMvq0MCbRk6GlYKwfzStrcP3/jSL8g==", + "requires": { + "@babel/highlight": "7.0.0-beta.44" + } + }, + "@babel/highlight": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.44.tgz", + "integrity": "sha512-Il19yJvy7vMFm8AVAh6OZzaFoAd0hbkeMZiX3P5HGD+z7dyI7RzndHB0dg6Urh/VAFfHtpOIzDUSxmY6coyZWQ==", + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^3.0.0" + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + } + } + }, + "@babel/traverse": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.44.tgz", + "integrity": "sha512-UHuDz8ukQkJCDASKHf+oDt3FVUzFd+QYfuBIsiNu/4+/ix6pP/C+uQZJ6K1oEfbCMv/IKWbgDEh7fcsnIE5AtA==", + "requires": { + "@babel/code-frame": "7.0.0-beta.44", + "@babel/generator": "7.0.0-beta.44", + "@babel/helper-function-name": "7.0.0-beta.44", + "@babel/helper-split-export-declaration": "7.0.0-beta.44", + "@babel/types": "7.0.0-beta.44", + "babylon": "7.0.0-beta.44", + "debug": "^3.1.0", + "globals": "^11.1.0", + "invariant": "^2.2.0", + "lodash": "^4.2.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz", + "integrity": "sha512-cuAuTTIQ9RqcFRJ/Y8PvTh+paepNcaGxwQwjIDRWPXmzzyAeCO4KqS9ikMvq0MCbRk6GlYKwfzStrcP3/jSL8g==", + "requires": { + "@babel/highlight": "7.0.0-beta.44" + } + }, + "@babel/highlight": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.44.tgz", + "integrity": "sha512-Il19yJvy7vMFm8AVAh6OZzaFoAd0hbkeMZiX3P5HGD+z7dyI7RzndHB0dg6Urh/VAFfHtpOIzDUSxmY6coyZWQ==", + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^3.0.0" + } + }, + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + } + } + }, + "@babel/types": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.44.tgz", + "integrity": "sha512-5eTV4WRmqbaFM3v9gHAIljEQJU4Ssc6fxL61JN+Oe2ga/BwyjzjamwkCVVAQjHGuAX8i0BWo42dshL8eO5KfLQ==", + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.2.0", + "to-fast-properties": "^2.0.0" + } + }, + "@discoveryjs/json-ext": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.5.tgz", + "integrity": "sha512-6nFkfkmSeV/rqSaS4oWHgmpnYw194f6hmWF5is6b0J1naJZoiD0NTc9AiUwPHvWsowkjuHErCZT1wa0jg+BLIA==", + "dev": true + }, + "@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" + } + } + }, + "@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "requires": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", + "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==" + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@rollup/plugin-commonjs": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-21.0.0.tgz", + "integrity": "sha512-XDQimjHl0kNotAV5lLo34XoygaI0teqiKGJ100B3iCU8+15YscJPeqk2KqkqD3NIe1H8ZTUo5lYjUFZyEgASTw==", + "requires": { + "@rollup/pluginutils": "^3.1.0", + "commondir": "^1.0.1", + "estree-walker": "^2.0.1", + "glob": "^7.1.6", + "is-reference": "^1.2.1", + "magic-string": "^0.25.7", + "resolve": "^1.17.0" + } + }, + "@rollup/plugin-eslint": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-eslint/-/plugin-eslint-8.0.1.tgz", + "integrity": "sha512-rTMAY4tKGBdbkHHQDaVhXNJg9tRmW7ihRAg7NQHiPUv13NFYBygIr+OYgpVNwSnGOH146BgCITSBAoMxMQGPTQ==", + "requires": { + "@rollup/pluginutils": "^4.0.0", + "eslint": "^7.12.0" + }, + "dependencies": { + "@rollup/pluginutils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.1.1.tgz", + "integrity": "sha512-clDjivHqWGXi7u+0d2r2sBi4Ie6VLEAzWMIkvJLnDmxoOhBYOTfzGbOQBA32THHm11/LiJbd01tJUpJsbshSWQ==", + "requires": { + "estree-walker": "^2.0.1", + "picomatch": "^2.2.2" + } + } + } + }, + "@rollup/plugin-json": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", + "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", + "requires": { + "@rollup/pluginutils": "^3.0.8" + } + }, + "@rollup/plugin-node-resolve": { + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.0.5.tgz", + "integrity": "sha512-mVaw6uxtvuGx/XCI4qBQXsDZJUfyx5vp39iE0J/7Hd6wDhEbjHr6aES7Nr9yWbuE0BY+oKp6N7Bq6jX5NCGNmQ==", + "requires": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.19.0" + } + }, + "@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "requires": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "dependencies": { + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" + } + } + }, + "@types/eslint": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.0.tgz", + "integrity": "sha512-07XlgzX0YJUn4iG1ocY4IX9DzKSmMGUs6ESKlxWhZRaa0fatIWaHWUVapcuGa8r5HFnTqzj+4OCjd5f7EZ/i/A==", + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.1.tgz", + "integrity": "sha512-SCFeogqiptms4Fg29WpOTk5nHIzfpKCemSN63ksBQYKTcXoJEmJagV+DhVmbapZzY4/5YaOV1nZwrsU79fFm1g==", + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" + }, + "@types/fs-extra": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.2.tgz", + "integrity": "sha512-SvSrYXfWSc7R4eqnOzbQF4TZmfpNSM9FrSWLU3EUnWBuyZqNBOrv1B1JA3byUDPUl9z4Ab3jeZG2eDdySlgNMg==", + "requires": { + "@types/node": "*" + } + }, + "@types/glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==", + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/json-schema": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", + "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==" + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" + }, + "@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==" + }, + "@types/node": { + "version": "16.10.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.3.tgz", + "integrity": "sha512-ho3Ruq+fFnBrZhUYI46n/bV2GjwzSkwuT4dTf0GkuNFmnb8nq4ny2z9JEVemFi6bdEJanHLlYfy9c6FN9B9McQ==" + }, + "@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "requires": { + "@types/node": "*" + } + }, + "@typescript-eslint/eslint-plugin": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz", + "integrity": "sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==", + "requires": { + "@typescript-eslint/experimental-utils": "4.33.0", + "@typescript-eslint/scope-manager": "4.33.0", + "debug": "^4.3.1", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.1.8", + "regexpp": "^3.1.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/eslint-plugin-tslint": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin-tslint/-/eslint-plugin-tslint-4.33.0.tgz", + "integrity": "sha512-o3ujMErtZJPgiNRETRJefo1bFNrloocOa5dMU49OW/G+Rq92IbXTY6FSF5MOwrdQK1X+VBEcA8y6PhUPWGlYqA==", + "requires": { + "@typescript-eslint/experimental-utils": "4.33.0", + "lodash": "^4.17.21" + } + }, + "@typescript-eslint/experimental-utils": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz", + "integrity": "sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==", + "requires": { + "@types/json-schema": "^7.0.7", + "@typescript-eslint/scope-manager": "4.33.0", + "@typescript-eslint/types": "4.33.0", + "@typescript-eslint/typescript-estree": "4.33.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz", + "integrity": "sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==", + "requires": { + "@typescript-eslint/scope-manager": "4.33.0", + "@typescript-eslint/types": "4.33.0", + "@typescript-eslint/typescript-estree": "4.33.0", + "debug": "^4.3.1" + } + }, + "@typescript-eslint/scope-manager": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz", + "integrity": "sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==", + "requires": { + "@typescript-eslint/types": "4.33.0", + "@typescript-eslint/visitor-keys": "4.33.0" + } + }, + "@typescript-eslint/types": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz", + "integrity": "sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==" + }, + "@typescript-eslint/typescript-estree": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz", + "integrity": "sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==", + "requires": { + "@typescript-eslint/types": "4.33.0", + "@typescript-eslint/visitor-keys": "4.33.0", + "debug": "^4.3.1", + "globby": "^11.0.3", + "is-glob": "^4.0.1", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz", + "integrity": "sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==", + "requires": { + "@typescript-eslint/types": "4.33.0", + "eslint-visitor-keys": "^2.0.0" + } + }, + "@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "requires": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==" + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==" + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==" + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==" + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==" + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@webpack-cli/configtest": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.0.tgz", + "integrity": "sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg==", + "dev": true, + "requires": {} + }, + "@webpack-cli/info": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.0.tgz", + "integrity": "sha512-F6b+Man0rwE4n0409FyAJHStYA5OIZERxmnUfLVwv0mc0V1wLad3V7jqRlMkgKBeAq07jUvglacNaa6g9lOpuw==", + "dev": true, + "requires": { + "envinfo": "^7.7.3" + } + }, + "@webpack-cli/serve": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.0.tgz", + "integrity": "sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA==", + "dev": true, + "requires": {} + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "requires": {} + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "requires": {} + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==" + }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==" + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==" + }, + "array-includes": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", + "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" + }, + "array.prototype.flat": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", + "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0" + } + }, + "array.prototype.flatmap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz", + "integrity": "sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0" + } + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==" + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, + "babel-eslint": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.6.tgz", + "integrity": "sha512-aCdHjhzcILdP8c9lej7hvXKvQieyRt20SF102SIGyY4cUIiw6UaAtK4j2o3dXX74jEmy0TJ0CEhv4fTIM3SzcA==", + "requires": { + "@babel/code-frame": "7.0.0-beta.44", + "@babel/traverse": "7.0.0-beta.44", + "@babel/types": "7.0.0-beta.44", + "babylon": "7.0.0-beta.44", + "eslint-scope": "3.7.1", + "eslint-visitor-keys": "^1.0.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz", + "integrity": "sha512-cuAuTTIQ9RqcFRJ/Y8PvTh+paepNcaGxwQwjIDRWPXmzzyAeCO4KqS9ikMvq0MCbRk6GlYKwfzStrcP3/jSL8g==", + "requires": { + "@babel/highlight": "7.0.0-beta.44" + } + }, + "@babel/highlight": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.44.tgz", + "integrity": "sha512-Il19yJvy7vMFm8AVAh6OZzaFoAd0hbkeMZiX3P5HGD+z7dyI7RzndHB0dg6Urh/VAFfHtpOIzDUSxmY6coyZWQ==", + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^3.0.0" + } + }, + "eslint-scope": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", + "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + } + } + }, + "babylon": { + "version": "7.0.0-beta.44", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz", + "integrity": "sha512-5Hlm13BJVAioCHpImtFqNOF2H3ieTOHd0fmFGMxOJ9jgeFqeAwsv3u5P5cR7CSeFrkgHsT19DgFJkHV0/Mcd8g==" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.3.tgz", + "integrity": "sha512-59IqHJV5VGdcJZ+GZ2hU5n4Kv3YiASzW6Xk5g9tf5a/MAzGeFwgGWU39fVzNIOVcgB3+Gp+kiQu0HEfTVU/3VQ==", + "requires": { + "caniuse-lite": "^1.0.30001264", + "electron-to-chromium": "^1.3.857", + "escalade": "^3.1.1", + "node-releases": "^1.1.77", + "picocolors": "^0.2.1" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "builtin-modules": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", + "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==" + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "requires": { + "callsites": "^0.2.0" + }, + "dependencies": { + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=" + } + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + }, + "caniuse-lite": { + "version": "1.0.30001265", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001265.tgz", + "integrity": "sha512-YzBnspggWV5hep1m9Z6sZVLOt7vrju8xWooFAgN6BA5qvy98qPAPb7vNUzypFaoh2pb3vlfzbDO8tB57UPGbtw==" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=" + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" + }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==" + }, + "clean-webpack-plugin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-4.0.0.tgz", + "integrity": "sha512-WuWE1nyTNAyW5T7oNyys2EN0cfP2fdRxhxnIQWiAp0bMabPdHhoGxM8A6YL2GhqwgrPnnaemVE7nv5XJ2Fhh2w==", + "requires": { + "del": "^4.1.1" + } + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==" + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "dependencies": { + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + } + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==" + }, + "command-line-args": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.0.tgz", + "integrity": "sha512-4zqtU1hYsSJzcJBOcNZIbW5Fbk9BkjCp1pZVhQKoRaWL5J7N4XphDLwo8aWwdQpTugxwu+jf9u2ZhkXiqp5Z6A==", + "requires": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + } + }, + "command-line-usage": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.1.tgz", + "integrity": "sha512-F59pEuAR9o1SF/bD0dQBDluhpT4jJQNWUHEuVBqpDmCUo6gPjCi+m9fCWnWZVR/oG6cMTUms4h+3NPl74wGXvA==", + "requires": { + "array-back": "^4.0.1", + "chalk": "^2.4.2", + "table-layout": "^1.0.1", + "typical": "^5.2.0" + }, + "dependencies": { + "array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==" + }, + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" + } + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "copy-webpack-plugin": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-9.0.1.tgz", + "integrity": "sha512-14gHKKdYIxF84jCEgPgYXCPpldbwpxxLbCmA7LReY7gvbaT555DgeBWBgBZM116tv/fO6RRJrsivBqRyRlukhw==", + "requires": { + "fast-glob": "^3.2.5", + "glob-parent": "^6.0.0", + "globby": "^11.0.3", + "normalize-path": "^3.0.0", + "p-limit": "^3.1.0", + "schema-utils": "^3.0.0", + "serialize-javascript": "^6.0.0" + } + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "requires": { + "ms": "2.1.2" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "requires": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + }, + "dependencies": { + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "requires": { + "array-uniq": "^1.0.1" + } + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } + } + } + } + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "peer": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "requires": { + "esutils": "^2.0.2" + } + }, + "electron-to-chromium": { + "version": "1.3.862", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.862.tgz", + "integrity": "sha512-o+FMbCD+hAUJ9S8bfz/FaqA0gE8OpCCm58KhhGogOEqiA1BLFSoVYLi+tW+S/ZavnqBn++n0XZm7HQiBVPs8Jg==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" + }, + "enhanced-resolve": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz", + "integrity": "sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA==", + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==" + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" + } + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "eslint-config-esnext": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-esnext/-/eslint-config-esnext-2.0.0.tgz", + "integrity": "sha1-PWyeh+0KDucvJ5cTjrC86yCJfKI=", + "requires": { + "babel-eslint": "^8.0.2", + "eslint": "^4.0.0", + "eslint-plugin-babel": "^4.1.2", + "eslint-plugin-import": "^2.8.0" + }, + "dependencies": { + "acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==" + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "requires": { + "acorn": "^3.0.4" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=" + } + } + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "ajv-keywords": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", + "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", + "requires": {} + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "requires": { + "esutils": "^2.0.2" + } + }, + "eslint": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.4.1.tgz", + "integrity": "sha1-mc1+r8/8ov+Zpcj18qR01jZLS9M=", + "requires": { + "ajv": "^5.2.0", + "babel-code-frame": "^6.22.0", + "chalk": "^1.1.3", + "concat-stream": "^1.6.0", + "cross-spawn": "^5.1.0", + "debug": "^2.6.8", + "doctrine": "^2.0.0", + "eslint-scope": "^3.7.1", + "espree": "^3.5.0", + "esquery": "^1.0.0", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^9.17.0", + "ignore": "^3.3.3", + "imurmurhash": "^0.1.4", + "inquirer": "^3.0.6", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.9.1", + "json-stable-stringify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^4.0.0", + "progress": "^2.0.0", + "require-uncached": "^1.0.3", + "semver": "^5.3.0", + "strip-json-comments": "~2.0.1", + "table": "^4.0.1", + "text-table": "~0.2.0" + } + }, + "eslint-plugin-babel": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-babel/-/eslint-plugin-babel-4.1.2.tgz", + "integrity": "sha1-eSAqDjV1fdkngJGbIzbx+i/lPB4=", + "requires": {} + }, + "eslint-plugin-import": { + "version": "2.24.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.24.2.tgz", + "integrity": "sha512-hNVtyhiEtZmpsabL4neEj+6M5DCLgpYyG9nzJY8lZQeQXEn5UPW1DpUdsMHMXsq98dbNm7nt1w9ZMSVpfJdi8Q==", + "requires": { + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.6.2", + "find-up": "^2.0.0", + "has": "^1.0.3", + "is-core-module": "^2.6.0", + "minimatch": "^3.0.4", + "object.values": "^1.1.4", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.11.0" + } + }, + "eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "requires": { + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" + } + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "requires": { + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "^2.0.0" + } + }, + "flat-cache": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", + "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "requires": { + "circular-json": "^0.3.1", + "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", + "write": "^0.2.1" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "requires": { + "p-limit": "^1.1.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + }, + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=" + }, + "string-width": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.0.0.tgz", + "integrity": "sha1-Y1xUNsxypuDDh87KJ41OLuxSaH4=", + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "table": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.1.tgz", + "integrity": "sha1-qBFsEz+sLGH0pCCrbN9cTWHw5DU=", + "requires": { + "ajv": "^4.7.0", + "ajv-keywords": "^1.0.0", + "chalk": "^1.1.1", + "lodash": "^4.0.0", + "slice-ansi": "0.0.4", + "string-width": "^2.0.0" + }, + "dependencies": { + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "requires": { + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" + } + } + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + } + } + }, + "eslint-config-recommended": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-recommended/-/eslint-config-recommended-2.0.0.tgz", + "integrity": "sha1-I1gX/da6j7A8/eOZWunm64+Y51Q=", + "requires": { + "babel-eslint": "^8.0.2", + "eslint": "^4.0.0", + "eslint-config-esnext": "^2.0.0", + "eslint-plugin-babel": "^4.1.2", + "eslint-plugin-import": "^2.8.0", + "eslint-plugin-react": "^7.5.0", + "eslint-plugin-react-native": "^3.2.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", + "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", + "requires": { + "@babel/highlight": "^7.14.5" + } + }, + "@babel/generator": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz", + "integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==", + "requires": { + "@babel/types": "^7.15.6", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz", + "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", + "requires": { + "@babel/helper-get-function-arity": "^7.15.4", + "@babel/template": "^7.15.4", + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz", + "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", + "requires": { + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz", + "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", + "requires": { + "@babel/types": "^7.15.4" + } + }, + "@babel/template": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz", + "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/parser": "^7.15.4", + "@babel/types": "^7.15.4" + } + }, + "@babel/traverse": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz", + "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.15.4", + "@babel/helper-function-name": "^7.15.4", + "@babel/helper-hoist-variables": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4", + "@babel/parser": "^7.15.4", + "@babel/types": "^7.15.4", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "requires": { + "ms": "2.1.2" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "@babel/types": { + "version": "7.15.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz", + "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", + "requires": { + "@babel/helper-validator-identifier": "^7.14.9", + "to-fast-properties": "^2.0.0" + } + }, + "acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==" + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "requires": { + "acorn": "^3.0.4" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=" + } + } + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "ajv-keywords": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", + "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", + "requires": {} + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "requires": { + "esutils": "^2.0.2" + } + }, + "eslint": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.4.1.tgz", + "integrity": "sha1-mc1+r8/8ov+Zpcj18qR01jZLS9M=", + "requires": { + "ajv": "^5.2.0", + "babel-code-frame": "^6.22.0", + "chalk": "^1.1.3", + "concat-stream": "^1.6.0", + "cross-spawn": "^5.1.0", + "debug": "^2.6.8", + "doctrine": "^2.0.0", + "eslint-scope": "^3.7.1", + "espree": "^3.5.0", + "esquery": "^1.0.0", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^9.17.0", + "ignore": "^3.3.3", + "imurmurhash": "^0.1.4", + "inquirer": "^3.0.6", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.9.1", + "json-stable-stringify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^4.0.0", + "progress": "^2.0.0", + "require-uncached": "^1.0.3", + "semver": "^5.3.0", + "strip-json-comments": "~2.0.1", + "table": "^4.0.1", + "text-table": "~0.2.0" + } + }, + "eslint-plugin-babel": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-babel/-/eslint-plugin-babel-4.1.2.tgz", + "integrity": "sha1-eSAqDjV1fdkngJGbIzbx+i/lPB4=", + "requires": {} + }, + "eslint-plugin-import": { + "version": "2.24.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.24.2.tgz", + "integrity": "sha512-hNVtyhiEtZmpsabL4neEj+6M5DCLgpYyG9nzJY8lZQeQXEn5UPW1DpUdsMHMXsq98dbNm7nt1w9ZMSVpfJdi8Q==", + "requires": { + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.6.2", + "find-up": "^2.0.0", + "has": "^1.0.3", + "is-core-module": "^2.6.0", + "minimatch": "^3.0.4", + "object.values": "^1.1.4", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.11.0" + } + }, + "eslint-plugin-react": { + "version": "7.26.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.26.1.tgz", + "integrity": "sha512-Lug0+NOFXeOE+ORZ5pbsh6mSKjBKXDXItUD2sQoT+5Yl0eoT82DqnXeTMfUare4QVCn9QwXbfzO/dBLjLXwVjQ==", + "requires": { + "array-includes": "^3.1.3", + "array.prototype.flatmap": "^1.2.4", + "doctrine": "^2.1.0", + "estraverse": "^5.2.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.0.4", + "object.entries": "^1.1.4", + "object.fromentries": "^2.0.4", + "object.hasown": "^1.0.0", + "object.values": "^1.1.4", + "prop-types": "^15.7.2", + "resolve": "^2.0.0-next.3", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.5" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" + }, + "resolve": { + "version": "2.0.0-next.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", + "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "eslint-plugin-react-native": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-native/-/eslint-plugin-react-native-3.11.0.tgz", + "integrity": "sha512-7F3OTwrtQPfPFd+VygqKA2VZ0f2fz0M4gJmry/TRE18JBb94/OtMxwbL7Oqwu7FGyrdeIOWnXQbBAveMcSTZIA==", + "requires": { + "@babel/traverse": "^7.7.4", + "eslint-plugin-react-native-globals": "^0.1.1" + } + }, + "eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "requires": { + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" + } + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "requires": { + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "^2.0.0" + } + }, + "flat-cache": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", + "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "requires": { + "circular-json": "^0.3.1", + "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", + "write": "^0.2.1" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "requires": { + "p-limit": "^1.1.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + }, + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "string-width": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.0.0.tgz", + "integrity": "sha1-Y1xUNsxypuDDh87KJ41OLuxSaH4=", + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "table": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.1.tgz", + "integrity": "sha1-qBFsEz+sLGH0pCCrbN9cTWHw5DU=", + "requires": { + "ajv": "^4.7.0", + "ajv-keywords": "^1.0.0", + "chalk": "^1.1.1", + "lodash": "^4.0.0", + "slice-ansi": "0.0.4", + "string-width": "^2.0.0" + }, + "dependencies": { + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "requires": { + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" + } + } + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + } + } + }, + "eslint-import-resolver-node": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "requires": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-module-utils": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.2.tgz", + "integrity": "sha512-QG8pcgThYOuqxupd06oYTZoNOGaUdTY1PqK+oS6ElF6vs4pBdk/aYxFVQQXzcrAqp9m7cl7lb2ubazX+g16k2Q==", + "requires": { + "debug": "^3.2.7", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "requires": { + "p-limit": "^1.1.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "requires": { + "find-up": "^2.1.0" + } + } + } + }, + "eslint-plugin-react-native-globals": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz", + "integrity": "sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g==" + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "requires": { + "eslint-visitor-keys": "^2.0.0" + } + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==" + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + }, + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "external-editor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", + "requires": { + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "tmp": "^0.0.33" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-glob": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", + "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "fastest-levenshtein": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", + "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", + "dev": true + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "requires": { + "reusify": "^1.0.4" + } + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "requires": { + "array-back": "^3.0.1" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "dependencies": { + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "flatted": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", + "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==" + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "requires": { + "is-glob": "^4.0.3" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "globals": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", + "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "requires": { + "type-fest": "^0.20.2" + } + }, + "globby": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", + "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + } + } + }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==" + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "import-local": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", + "integrity": "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.4", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rx-lite": "^4.0.8", + "rx-lite-aggregates": "^4.0.8", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "dev": true + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "^1.0.0" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" + }, + "is-core-module": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.7.0.tgz", + "integrity": "sha512-ByY+tjCciCr+9nLryBYcSD50EOGWt95c7tIsKTG1J2ixKKXPvF7Ej3AVd+UfDydAJom3biBGDBALaO79ktwgEQ==", + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=" + }, + "is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-number-object": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", + "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==" + }, + "is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "requires": { + "is-path-inside": "^2.1.0" + } + }, + "is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "requires": { + "path-is-inside": "^1.0.2" + } + }, + "is-plain-object": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", + "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==" + }, + "is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "requires": { + "@types/estree": "*" + } + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==" + }, + "is-shared-array-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", + "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==" + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-weakref": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", + "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", + "requires": { + "call-bind": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "jest-worker": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.2.5.tgz", + "integrity": "sha512-HTjEPZtcNKZ4LnhSp02NEH4vE+5OpJ0EsOWYvGQpHgUMLngydESAAMH5Wd/asPf29+XUDQZszxpLg1BkIIA2aw==", + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "requires": { + "jsonify": "~0.0.0" + } + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "requires": { + "minimist": "^1.2.5" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" + }, + "jsx-ast-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz", + "integrity": "sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==", + "requires": { + "array-includes": "^3.1.3", + "object.assign": "^4.1.2" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + } + } + }, + "loader-runner": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", + "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==" + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=" + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "magic-string": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", + "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "mime-db": { + "version": "1.50.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", + "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==" + }, + "mime-types": { + "version": "2.1.33", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", + "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", + "requires": { + "mime-db": "1.50.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node-loader": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/node-loader/-/node-loader-2.0.0.tgz", + "integrity": "sha512-I5VN34NO4/5UYJaUBtkrODPWxbobrE4hgDqPrjB25yPkonFhCmZ146vTH+Zg417E9Iwoh1l/MbRs1apc5J295Q==", + "requires": { + "loader-utils": "^2.0.0" + } + }, + "node-releases": { + "version": "1.1.77", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz", + "integrity": "sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ==" + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-inspect": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "object.fromentries": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "object.hasown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.0.tgz", + "integrity": "sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "object.values": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + }, + "dependencies": { + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + } + } + }, + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==" + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + }, + "picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "requires": { + "find-up": "^2.1.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "requires": { + "p-limit": "^1.1.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + } + } + }, + "pluralize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-4.0.0.tgz", + "integrity": "sha1-WbcIwcAZCi9pLxx2GMRGsFL9F2I=" + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" + }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "dependencies": { + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + } + } + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "requires": { + "p-limit": "^1.1.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + } + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "dev": true, + "requires": { + "resolve": "^1.9.0" + } + }, + "reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==" + }, + "regexp.prototype.flags": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", + "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==" + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "requires": { + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=" + } + } + }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + }, + "dependencies": { + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "requires": { + "mimic-fn": "^1.0.0" + } + } + } + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + }, + "rollup": { + "version": "2.58.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.58.0.tgz", + "integrity": "sha512-NOXpusKnaRpbS7ZVSzcEXqxcLDOagN6iFS8p45RkoiMqPHDLwJm758UF05KlMoCRbLBTZsPOIa887gZJ1AiXvw==", + "requires": { + "fsevents": "~2.3.2" + } + }, + "rollup-plugin-copy": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.4.0.tgz", + "integrity": "sha512-rGUmYYsYsceRJRqLVlE9FivJMxJ7X6jDlP79fmFkL8sJs7VVMSVyA2yfyL+PGyO/vJs4A87hwhgVfz61njI+uQ==", + "requires": { + "@types/fs-extra": "^8.0.1", + "colorette": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "10.0.1", + "is-plain-object": "^3.0.0" + }, + "dependencies": { + "globby": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", + "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + } + } + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==" + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rx-lite": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=" + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "requires": { + "rx-lite": "*" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "requires": { + "randombytes": "^2.1.0" + } + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", + "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==" + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + } + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-support": { + "version": "0.5.20", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", + "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz", + "integrity": "sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==" + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "string.prototype.matchall": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz", + "integrity": "sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.3.1", + "side-channel": "^1.0.4" + } + }, + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.2.tgz", + "integrity": "sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g==", + "requires": { + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ajv": { + "version": "8.6.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", + "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + } + } + }, + "table-layout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", + "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", + "requires": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + }, + "dependencies": { + "array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==" + }, + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" + } + } + }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" + }, + "terser": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.9.0.tgz", + "integrity": "sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ==", + "requires": { + "commander": "^2.20.0", + "source-map": "~0.7.2", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + } + } + }, + "terser-webpack-plugin": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.2.4.tgz", + "integrity": "sha512-E2CkNMN+1cho04YpdANyRrn8CyN4yMy+WdFKZIySFZrGXZxJwJP6PMNGGc/Mcr6qygQHUUqRxnAPmi0M9f00XA==", + "requires": { + "jest-worker": "^27.0.6", + "p-limit": "^3.1.0", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1", + "terser": "^5.7.2" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" + }, + "tsconfig-paths": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz", + "integrity": "sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==", + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + } + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "tslint": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", + "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", + "peer": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.3", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.13.0", + "tsutils": "^2.29.0" + }, + "dependencies": { + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "peer": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "peer": true + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "peer": true, + "requires": { + "tslib": "^1.8.1" + } + } + } + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "requires": { + "tslib": "^1.8.1" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "typescript": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz", + "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==" + }, + "typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==" + }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==" + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "watchpack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz", + "integrity": "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==", + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "webpack": { + "version": "5.58.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.58.1.tgz", + "integrity": "sha512-4Z/dmbTU+VmkCb2XNgW7wkE5TfEcSooclprn/UEuVeAkwHhn07OcgUsyaKHGtCY/VobjnsYBlyhKeMLiSoOqPg==", + "requires": { + "@types/eslint-scope": "^3.7.0", + "@types/estree": "^0.0.50", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.4.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.8.3", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.4", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.2.0", + "webpack-sources": "^3.2.0" + }, + "dependencies": { + "@types/estree": { + "version": "0.0.50", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", + "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==" + }, + "acorn": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", + "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==" + }, + "acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "requires": {} + } + } + }, + "webpack-cli": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.0.tgz", + "integrity": "sha512-n/jZZBMzVEl4PYIBs+auy2WI0WTQ74EnJDiyD98O2JZY6IVIHJNitkYp/uTXOviIOMfgzrNvC9foKv/8o8KSZw==", + "dev": true, + "requires": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.1.0", + "@webpack-cli/info": "^1.4.0", + "@webpack-cli/serve": "^1.6.0", + "colorette": "^2.0.14", + "commander": "^7.0.0", + "execa": "^5.0.0", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "v8-compile-cache": "^2.2.0", + "webpack-merge": "^5.7.3" + }, + "dependencies": { + "colorette": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", + "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", + "dev": true + }, + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true + } + } + }, + "webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + } + }, + "webpack-sources": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.1.tgz", + "integrity": "sha512-t6BMVLQ0AkjBOoRTZgqrWm7xbXMBzD+XDq2EZ96+vMfn3qKgsvdXZhbPZ4ElUOpdv4u+iiGe+w3+J75iy/bYGA==" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + }, + "wordwrapjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", + "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", + "requires": { + "reduce-flatten": "^2.0.0", + "typical": "^5.2.0" + }, + "dependencies": { + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "requires": { + "mkdirp": "^0.5.1" + } + }, + "xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + } + } +} diff --git a/javascript/cl/ESLintRunner/package.json b/javascript/cl/ESLintRunner/package.json index 5594013..cd61f65 100644 --- a/javascript/cl/ESLintRunner/package.json +++ b/javascript/cl/ESLintRunner/package.json @@ -5,16 +5,35 @@ "main": "ESLintRunner.js", "private": true, "dependencies": { - "JSONStream": "1.3.3", - "command-line-args": "5.0.2", - "command-line-usage": "5.0.5", - "eslint": "5.9.0", - "espree": "4.1.0", - "hashmap": "2.3.0", - "jsonfile": "3.0.1", - "xml2js": "0.4.19" + "@typescript-eslint/eslint-plugin": "^4.33.0", + "@typescript-eslint/eslint-plugin-tslint": "^4.33.0", + "@typescript-eslint/parser": "^4.33.0", + "@typescript-eslint/typescript-estree": "^4.33.0", + "clean-webpack-plugin": "^4.0.0", + "command-line-args": "5.2.0", + "command-line-usage": "6.1.1", + "copy-webpack-plugin": "^9.0.1", + "eslint": "^7.5.0", + "eslint-config-react-app": "^6.0.0", + "eslint-plugin-flowtype": "^5.2.0", + "eslint-plugin-import": "^2.22.0", + "eslint-plugin-jsx-a11y": "^6.3.1", + "eslint-plugin-react": "^7.20.3", + "eslint-plugin-react-hooks": "^4.0.8", + "node-loader": "2.0.0", + "typescript": "^4.4.3", + "webpack-node-externals": "^3.0.0", + "xml2js": "0.4.23", + "eslint-plugin-angular": "^4.1.0", + "json5": "^2.2.0" }, "scripts": { - "analyze": "node ESLintRunner.js" + "start": "node fix_esquery.js && webpack --config webpack.dev.js", + "build": "node fix_esquery.js && webpack --config webpack.prod.js" + }, + "devDependencies": { + "webpack": "^5.45.1", + "webpack-cli": "^4.7.2", + "webpack-merge": "^5.8.0" } } diff --git a/javascript/cl/ESLintRunner/src/assets/constants.js b/javascript/cl/ESLintRunner/src/assets/constants.js new file mode 100644 index 0000000..6ae4bb7 --- /dev/null +++ b/javascript/cl/ESLintRunner/src/assets/constants.js @@ -0,0 +1,23 @@ +const INPUT = 'input'; +const USE_RELATIVE_PATH = 'useRelativePath'; +const OUTPUT = 'out'; +const RUL = 'rul'; +const HELP = 'help'; +const STAT = 'stat'; +const IGNORE_NODE_MODULES = 'ignoreNodeModules'; +const RAW_OUTPUT = 'raw'; +const MODULE_BASED_ANALYSIS = 'moduleBasedAnalysis'; +const EXTERNAL_HARD_FILTER = 'externalHardFilter'; + +export { + INPUT, + USE_RELATIVE_PATH, + OUTPUT, + RUL, + HELP, + STAT, + IGNORE_NODE_MODULES, + RAW_OUTPUT, + MODULE_BASED_ANALYSIS, + EXTERNAL_HARD_FILTER +} diff --git a/javascript/cl/ESLintRunner/src/assets/options.js b/javascript/cl/ESLintRunner/src/assets/options.js index cfe28e7..9cd7d71 100644 --- a/javascript/cl/ESLintRunner/src/assets/options.js +++ b/javascript/cl/ESLintRunner/src/assets/options.js @@ -18,16 +18,19 @@ * limitations under the Licence. */ -const fs = require('fs'); -const path = require('path'); -const getUsage = require('command-line-usage'); //for printing the usage -const commandLineArgs = require('command-line-args'); //for parsing command line args -const toolDescription = require('./toolDescription'); //Tool description +import * as fs from 'fs'; +import * as path from 'path'; +import {default as getUsage} from 'command-line-usage'; //for printing the usage +import {default as commandLineArgs} from 'command-line-args'; //for parsing command line args +import * as toolDescription from './toolDescription.js'; +import * as constants from "./constants.js"; +import {MODULE_BASED_ANALYSIS} from "./constants.js"; + //List of command line options const definitions = [ { - name: 'input', + name: constants.INPUT, alias: 'i', type: String, multiple: true, @@ -35,7 +38,7 @@ const definitions = [ description: 'Input file(s) or directory to be analyzed. Note: simply giving the input file(s) or directory after the last command line parameter will have the same effect too.' }, { - name: 'useRelativePath', + name: constants.USE_RELATIVE_PATH, alias: 'r', type: Boolean, defaultValue: false, @@ -43,31 +46,56 @@ const definitions = [ }, { - name: 'out', + name: constants.OUTPUT, alias: 'o', type: String, description: 'The output filename for the generated XML-Graph to be saved in.' }, { - name: 'rul', + name: constants.RUL, type: String, defaultValue: false, - description: 'Input RUL file, which contains the exluded and included rules.' + description: 'Input RUL file, which contains the excluded and included rules.' }, { - name: 'help', + name: constants.HELP, alias: 'h', type: Boolean, defaultValue: false, description: 'Prints out this help screen of EsLintRunner.' }, { - name: 'stat', + name: constants.STAT, type: String, description: 'Write memory and runtime stats to the given file.', defaultValue: false + }, + { + name: constants.IGNORE_NODE_MODULES, + alias: 'n', + type: Boolean, + description: 'Ignore all node_modules folder.', + defaultValue: false + }, + { + name: constants.RAW_OUTPUT, + type: Boolean, + description: 'Save raw results into JSON.', + defaultValue: false + }, + { + name: constants.MODULE_BASED_ANALYSIS, + type: Boolean, + description: 'Use module-based analysis instead of file-based analysis', + defaultValue: true // Change this to false if you want to use file based analysis. + }, + { + name: constants.EXTERNAL_HARD_FILTER, + alias: 'e', + defaultValue: false, + type: String, + description: 'Filter file specified with relative or absolute path, to filter out certain files from the analysis based on their path names. Filtered files will not appear in the results.' } - ]; //sections of usage @@ -88,53 +116,36 @@ const sections = [ const usage = getUsage(sections); //construction of usage text +//Exports function printUsage() { console.log(usage); } -//recursive function which fill the input list -function constructInputList(inputFile, parsedOptions) { - if (fs.lstatSync(inputFile).isDirectory()) { - var dirContent = fs.readdirSync(inputFile); - for (var i = 0; i < dirContent.length; i++) { - constructInputList(path.join(inputFile, dirContent[i]), parsedOptions); - } - } else { - if (path.extname(inputFile) !== ".js" && path.extname(inputFile) !== ".html") { - return; - } - - parsedOptions.inputList.push(inputFile); - } -} - -//Exports -module.exports.printUsage = printUsage; -module.exports.parse = function () { - if (process.argv.length == 2) { +function parse() { + if (process.argv.length === 2) { printUsage(); } - var options; + let options; try { options = commandLineArgs(definitions); options = checkOptions(options); - } - catch (e) { + } catch (e) { console.error(e); console.error("The given command line arguments was bad. Please use the --help switch to read documentations."); process.exit(); } - - //get all input files (dirs turned into files to be analyzed) options.inputList = []; + options.filteredFiles = []; for (let i = 0; i < options.input.length; i++) { + //check if inputs have .ts files constructInputList(options.input[i], options); + if (MODULE_BASED_ANALYSIS && options.externalHardFilter) { + hardFilterChecking(options.input[i], options); + } } - return options; } - //checks whether the parsed command line options are correct function checkOptions(parsedOptions) { //help and default screen @@ -146,11 +157,143 @@ function checkOptions(parsedOptions) { console.error("The --input (-i) parameter is required."); process.exit(); } + if (!parsedOptions.out) { console.error("The --out (-o) parameter is required."); process.exit(); } + if (parsedOptions.externalHardFilter) { + parsedOptions.hardFilterArray = getHardFilterFiles(parsedOptions.externalHardFilter); + } return parsedOptions; } +function constructInputList(inputFile, parsedOptions) { + if (!fs.existsSync(inputFile)) { + console.log(`${inputFile} is missing, skipping this file/directory.`); + return; + } + + if (parsedOptions[constants.IGNORE_NODE_MODULES] && inputFile.includes("node_modules")) { + return; + } + + if (fs.lstatSync(inputFile).isDirectory()) { + if (parsedOptions[constants.MODULE_BASED_ANALYSIS]) { + parsedOptions.inputList.push(path.resolve(inputFile)); + return; + } + const dirContent = fs.readdirSync(inputFile); + for (let i = 0; i < dirContent.length; i++) { + constructInputList(path.join(inputFile, dirContent[i]), parsedOptions); + } + } else { + if ((path.extname(inputFile) !== ".js" && path.extname(inputFile) !== ".jsx" && path.extname(inputFile) !== ".ts" && path.extname(inputFile) !== ".tsx") || externalHardFiltering(inputFile, parsedOptions.hardFilterArray, parsedOptions.filteredFiles)) { + return; + } + parsedOptions.inputList.push(inputFile); + } +} + +/** + * Filters files based on the external hard filter when module based analysis is used. + * Mostly the same as constructInputList, but files passing the filter aren't added to the input list. + * @param inputFile + * @param parsedOptions + */ +function hardFilterChecking(inputFile, parsedOptions) { + if (!fs.existsSync(inputFile)) { + console.log(`${inputFile} is missing, skipping this file/directory.`); + return; + } + + if (parsedOptions[constants.IGNORE_NODE_MODULES] && inputFile.includes("node_modules")) { + return; + } + if (fs.lstatSync(inputFile).isDirectory()) { + const dirContent = fs.readdirSync(inputFile); + for (let i = 0; i < dirContent.length; i++) { + hardFilterChecking(path.join(inputFile, dirContent[i]), parsedOptions); + } + } else { + if ((path.extname(inputFile) !== ".js" && path.extname(inputFile) !== ".jsx" && path.extname(inputFile) !== ".ts" && path.extname(inputFile) !== ".tsx") || externalHardFiltering(inputFile, parsedOptions.hardFilterArray, parsedOptions.filteredFiles)) { + return; + } + } +} + +/** + * Filters files based on the external hard filter + * @param: inputFile: absolute path of a file (!) + * @param: hardFilterArray: contains the regex formulas from the external hard filter + * @param: filteredArray: An array that contains files that were filtered. + * */ +function externalHardFiltering(inputFile, hardFilterArray, filteredArray) { + if (!hardFilterArray) { + return; + } + let filterIt = false; + for (let i = 0; i < hardFilterArray.length; i++) { + if (inputFile.match(hardFilterArray[i].regex)) { + filterIt = hardFilterArray[i].filter; + } + } + if (filterIt) { + let splitPath = inputFile.split('\\'); + filteredArray.push(splitPath[splitPath.length - 1]); + } + return filterIt; +} + +/** + * Collects the regexp formulas from the filter file and stores them in an array (hardFilterArray) + * @param hardFilterFile the path/name of the hard filter (.txt) + */ +function getHardFilterFiles(hardFilterFile) { + let hardFilterArray = []; + let filterPath; + if (!path.isAbsolute(hardFilterFile)) { + filterPath = path.resolve(hardFilterFile); + } else { + filterPath = hardFilterFile; + } + if (!fs.existsSync(filterPath)) { + console.warn("Hard filter file: " + hardFilterFile + " does not exist. Filtering step is being skipped."); + return hardFilterArray; + } + + if (fs.lstatSync(filterPath).isFile() && path.extname(filterPath) === ".txt") { + fs.readFileSync(filterPath).toString().split('\n').forEach(function (line) { + //if empty line then continue + if (line.trim().length === 0) { + return; + } + let firstChar = line.substring(0, 1); + let regex = line.substring(1, line.length); + if (regex.endsWith("\r")) { + regex = regex.substring(0, regex.length - 1); + } + regex = ".*" + regex + ".*"; + + if (firstChar === "-") { + hardFilterArray.push({regex: regex, filter: true}); + } else if (firstChar === "+") { + hardFilterArray.push({regex: regex, filter: false}); + } else if (firstChar !== "#") { + console.error("External hard filter contains an invalid line: " + line + "\n"); + return; + } + + }); + } else { + console.error("Hard filter file does not exist or not a file! Skipping filtering step."); + } + + return hardFilterArray; +} + +export { + printUsage, + parse +} diff --git a/javascript/cl/ESLintRunner/src/assets/toolDescription.js b/javascript/cl/ESLintRunner/src/assets/toolDescription.js index 5caa860..881f933 100644 --- a/javascript/cl/ESLintRunner/src/assets/toolDescription.js +++ b/javascript/cl/ESLintRunner/src/assets/toolDescription.js @@ -18,11 +18,12 @@ * limitations under the Licence. */ -module.exports.banner = "" + +const banner = "" + " ___ ___ _ _ _ ___ \n" + "| __>/ __>| | <_>._ _ _| |_ | . \\ _ _ ._ _ ._ _ ___ _ _ \n" + "| _> \\__ \\| |_ | || ' | | | | /| | || ' || ' |/ ._>| '_> \n" + "|___><___/|___||_||_|_| |_| |_\\_\\`___||_|_||_|_|\\___.|_| \n"; -module.exports.header = 'EsLintRunner - A tool, which can parse the AST for ESLint'; -module.exports.description = 'The EsLintRunner can parse AST for ESLint, which can generate a Columbus-style ESLintToGraph XML.' +const header = 'EsLintRunner - A tool, which can parse the AST for ESLint'; +const description = 'The EsLintRunner can parse AST for ESLint, which can generate a Columbus-style ESLintToGraph XML.' +export {banner, header, description} diff --git a/javascript/cl/ESLintRunner/src/globals.js b/javascript/cl/ESLintRunner/src/globals.js index ef28924..546b401 100644 --- a/javascript/cl/ESLintRunner/src/globals.js +++ b/javascript/cl/ESLintRunner/src/globals.js @@ -18,101 +18,32 @@ * limitations under the Licence. */ -const hashmap = require('hashmap'); -const path = require('path'); - - -var nodeAndWrapperMap = new hashmap(); -var actualFile = undefined; -var options = undefined; -var previousNode = null; - -module.exports.prevNode = function () { - return previousNode; -}; - -module.exports.resetPrevNode = function () { - previousNode = null; -}; - -module.exports.setPrevNode = function (node) { - previousNode = node; -}; - -module.exports.setActualFile = function (filename) { - actualFile = filename; -}; - -module.exports.getActualFile = function () { - return actualFile; -}; - -module.exports.putNodeWrapperPair = function (node, wrapper) { - nodeAndWrapperMap.set(node, wrapper); -}; +/** + * Version number that will be in the output XML + * @type {number} + */ +const ESLINTRUNNNER_VERSION = 4.3; -module.exports.getWrapperOfNode = function (node) { - return nodeAndWrapperMap.get(node);//returns the wrapper -}; +let options = undefined; -module.exports.setOptions = function (opt) { +function setOptions(opt) { options = opt; -}; +} -module.exports.getOptions = function () { +function getOptions() { return options; -}; +} -module.exports.getOption = function (obj) { - if (options !== undefined) - if (obj in options) - return options[obj]; - return false; -}; - -module.exports.setPositionInfo = function (node, wrapper) { - try { - if (options.useRelativePath) { - wrapper.setPath(path.relative(process.cwd(), actualFile)); - } - else { - wrapper.setPath(actualFile); - } - - //A JS file always starts from 1,1 (line, column) - if (node.type === "Program") { - wrapper.setLine(1); - wrapper.setCol(1); - wrapper.setWideLine(1); - wrapper.setWideCol(1); - } - else { - wrapper.setLine(node.loc.start.line); - wrapper.setCol(node.loc.start.column); - wrapper.setWideLine(node.loc.start.line); - wrapper.setWideCol(node.loc.start.column); - } - - wrapper.setEndLine(node.loc.end.line); - wrapper.setEndCol(node.loc.end.column); - wrapper.setWideEndLine(node.loc.end.line); - wrapper.setWideEndCol(node.loc.end.column); - } catch (e) { - console.error(node.type + " - Position cannot be set! Reason of the error: " + e + "\n"); +function getOption(obj) { + if (options !== undefined && obj in options) { + return options[obj]; } -}; - - -module.exports.getLiteralType = function (node) { - if (typeof (node.value) !== "object") { - var type = typeof (node.value); - return type.charAt(0).toLocaleUpperCase() + type.substring(1, type.length); - } else { - if (node.raw === "null") { - return "Null"; - } else if (node.regex != null) { - return "RegExp"; - } - } - -}; + return false; +} + +export { + setOptions, + getOptions, + getOption, + ESLINTRUNNNER_VERSION +} diff --git a/javascript/cl/ESLintRunner/typescript-eslint.json b/javascript/cl/ESLintRunner/typescript-eslint.json new file mode 100644 index 0000000..2710cc2 --- /dev/null +++ b/javascript/cl/ESLintRunner/typescript-eslint.json @@ -0,0 +1,477 @@ +{ "for-direction": 0, + "getter-return": [ 0, { "allowImplicit": true } ], + "no-await-in-loop": 0, + "no-compare-neg-zero": 1, + "no-cond-assign": [ 1, "except-parens" ], + "no-console": [ 1, { "allow": [ "warn", "error" ] } ], + "no-constant-condition": [ 1, { "checkLoops": true } ], + "no-control-regex": 1, + "no-debugger": 1, + "no-dupe-args": 1, + "no-dupe-keys": 1, + "no-duplicate-case": 1, + "no-empty": [ 1, { "allowEmptyCatch": true } ], + "no-empty-character-class": 1, + "no-ex-assign": 1, + "no-extra-boolean-cast": 1, + "no-extra-parens": 0, + "@typescript-eslint/no-extra-parens": [0, "all"], + "no-extra-semi": 0, + "@typescript-eslint/no-extra-semi": 1, + "no-func-assign": 1, + "no-inner-declarations": [ 1, "functions" ], + "no-invalid-regexp": + [ 1, + { "allowConstructorFlags": [ "u", "y" ] } + ], + "no-irregular-whitespace": [ 1, { "skipStrings": true } ], + "no-obj-calls": 1, + "no-prototype-builtins": 0, + "no-regex-spaces": 1, + "no-sparse-arrays": 1, + "no-template-curly-in-string": 0, + "no-unexpected-multiline": 1, + "no-unreachable": 1, + "no-unsafe-finally": 1, + "no-unsafe-negation": 1, + "use-isnan": 1, + "valid-jsdoc": [ 0, { "requireReturn": false } ], + "valid-typeof": [ 1, { "requireStringLiterals": true } ], + "accessor-pairs": [ 0, { "setWithoutGet": true, "getWithoutSet": false } ], + "array-callback-return": [ 0, { "allowImplicit": false } ], + "block-scoped-var": 0, + "class-methods-use-this": 0, + "complexity": [ 0, { "max": 2 } ], + "consistent-return": [ 0, { "treatUndefinedAsUnspecified": false } ], + "curly": [ 0, "all" ], + "default-case": [ 0, { "commentPattern": "/^no default$/i" } ], + "dot-location": [ 0, "object" ], + "dot-notation": 0, + "@typescript-eslint/dot-notation": [ 0, { "allowKeywords": true } ], + "eqeqeq": [ 1, "always" ], + "guard-for-in": 0, + "no-alert": 0, + "no-caller": 0, + "no-case-declarations": 1, + "no-div-regex": 0, + "no-else-return": [ 0, { "allowElseIf": true } ], + "no-empty-function": 0, + "@typescript-eslint/no-empty-function": [ 0, { "allow": [] } ], + "no-empty-pattern": 1, + "no-eq-null": 0, + "no-eval": [ 0, { "allowIndirect": true } ], + "no-extend-native": [ 0, { "exceptions": [ ] } ], + "no-extra-bind": 0, + "no-extra-label": 0, + "no-fallthrough": [ 1, { "commentPattern": "break[\\s\\w]*omitted" } ], + "no-floating-decimal": 0, + "no-global-assign": [ 1, { "exceptions": [ "Object"] } ], + "no-implicit-coercion": + [ 0, + { "boolean": true, + "number": true, + "string": true, + "allow": [ ] } + ], + "no-implicit-globals": 0, + "no-implied-eval": 0, + "@typescript-eslint/no-implied-eval": 0, + "no-invalid-this": 0, + "@typescript-eslint/no-invalid-this": 0, + "no-iterator": 1, + "no-labels": [ 0, { "allowLoop": false, "allowSwitch": false } ], + "no-lone-blocks": 0, + "no-loop-func": 0, + "@typescript-eslint/no-loop-func": 0, + "no-magic-numbers":0, + "@typescript-eslint/no-magic-numbers": [ 1, + { "ignore": [ ], + "ignoreArrayIndexes": false, + "enforceConst": false, + "detectObjects": false } + ], + "no-multi-spaces": [ 0, { "ignoreEOLComments": false, "exceptions": {} } ], + "no-multi-str": 0, + "no-new": 0, + "no-new-func": 0, + "no-new-wrappers": 1, + "no-octal": 1, + "no-octal-escape": 0, + "no-param-reassign": + [ 0, + { "props": false, + "ignorePropertyModificationsFor": [ ] } + ], + "no-proto": 0, + "no-redeclare": 0, + "@typescript-eslint/no-redeclare": [ 1, { "builtinGlobals": false } ], + "no-restricted-properties": 0, + "no-return-assign": [ 0, "always" ], + "no-return-await": 0, + "no-script-url": 0, + "no-self-assign": [ 1, { "props": false } ], + "no-self-compare": 0, + "no-sequences": 0, + "no-throw-literal": 0, + "@typescript-eslint/no-throw-literal": 0, + "no-unmodified-loop-condition": 0, + "no-unused-expressions": 0, + "@typescript-eslint/no-unused-expressions": + [ 0, + { "allowShortCircuit": false, + "allowTernary": false, + "allowTaggedTemplates": false } + ], + "no-unused-labels": 1, + "no-useless-call": 0, + "no-useless-concat": 0, + "no-useless-escape": 1, + "no-useless-return": 0, + "no-void": 0, + "no-warning-comments": + [ 0, + { "terms": [ "todo", "fixme", "xxx" ], + "location": "start" } + ], + "no-with": 0, + "prefer-promise-reject-errors": 0, + "radix": [ 0, "always" ], + "require-await": 0, + "@typescript-eslint/require-await":0, + "vars-on-top": 0, + "wrap-iife": [ 0, "outside" ], + "yoda": [ 0, "never" ], + "strict": [ 0, "safe" ], + "init-declarations": 0, + "@typescript-eslint/init-declarations": [ 0, { "ignoreForLoopInit": true } ], + "no-catch-shadow": 0, + "no-delete-var": 1, + "no-label-var": 0, + "no-restricted-globals": [ 0, "event" ], + "no-shadow": 0, + "@typescript-eslint/no-shadow": 0, + "no-shadow-restricted-names": 0, + "no-undef": [ 1, { "typeof": false } ], + "no-undef-init": 0, + "no-undefined": 0, + "no-unused-vars": 0, + "@typescript-eslint/no-unused-vars": [ 1, { "vars": "all", "args": "after-used" } ], + "no-use-before-define": 0, + "@typescript-eslint/no-use-before-define": + [ 0, + { "functions": true, + "classes": true, + "variables": true, + "enums": true, + "typedefs": true, + "ignoreTypeReferences": true + } + ], + "callback-return": 0, + "global-require": 0, + "handle-callback-err": [ 0, "err" ], + "no-buffer-constructor": [ 0, "err" ], + "no-mixed-requires": [ 0, { "grouping": false, "allowCall": false } ], + "no-new-require": 0, + "no-path-concat": 0, + "no-process-env": 0, + "no-process-exit": 0, + "no-restricted-modules": [ 0, { "paths": [ ] } ], + "no-sync": [ 0, { "allowAtRootLevel": false } ], + "array-bracket-newline": [ 0, { "multiline": true, "minItems": 2 } ], + "array-bracket-spacing": [ 0, "always" ], + "array-element-newline": [ 0, "always" ], + "block-spacing": [ 0, "always" ], + "brace-style": 0, + "@typescript-eslint/brace-style": [ 0, "1tbs" ], + "camelcase": [ 0, { "properties": "always" } ], + "capitalized-comments": [ 0, "always" ], + "comma-dangle": 0, + "@typescript-eslint/comma-dangle": + [ 0, + { "arrays": "never", + "objects": "never", + "imports": "never", + "exports": "never", + "functions": "ignore", + "enums": "never", + "generics": "never", + "tuples": "never"} + ], + "comma-spacing": [ 0, { "before": false, "after": true } ], + "comma-style": [ 0, "last" ], + "computed-property-spacing": [ 0, "always" ], + "consistent-this": [ 0, "that" ], + "eol-last": [ 0, "always" ], + "func-call-spacing": 0, + "@typescript-eslint/func-call-spacing": [ 0, "never" ], + "func-name-matching": [ 0, "always" ], + "func-names": [ 0, "always" ], + "func-style": [ 0, "expression" ], + "function-paren-newline": [ 0, "multiline" ], + "id-blacklist": [ 0, "data" ], + "id-length": [ 0, { "min": 2, "properties": "always" } ], + "id-match": [ 0, "^[a-z]+([A-Z][a-z]+)*$" ], + "implicit-arrow-linebreak": [ 0, "beside" ], + "indent": 0, + "@typescript-eslint/indent": [ 0, 2 ], + "jsx-quotes": 0, + "key-spacing": + [ 0, + { "beforeColon": false, "afterColon": true, "mode": "strict" } + ], + "keyword-spacing": 0, + "@typescript-eslint/keyword-spacing": [ 0, { "before": true, "after": true, "overrides": {} } ], + "line-comment-position": [ 0, { "position": "above" } ], + "linebreak-style": [ 0, "unix" ], + "lines-around-comment": [ 0, { "beforeBlockComment": true } ], + "lines-between-class-members": 0, + "@typescript-eslint/lines-between-class-members": [ 0, "always" ], + "max-depth": [ 0, { "max": 4 } ], + "max-len": + [ 0, + { "code": 80, + "tabWidth": 4, + "comments": 65, + "ignoreComments": true, + "ignoreTrailingComments": true, + "ignoreUrls": true, + "ignoreStrings": true, + "ignoreTemplateLiterals": true, + "ignoreRegExpLiterals": true } + ], + "max-lines": + [ 0, + { "max": 300, "skipBlankLines": true, "skipComments": true } + ], + "max-nested-callbacks": [ 0, { "max": 10 } ], + "max-params": [ 0, { "max": 3 } ], + "max-statements": [ 0, { "max": 10 } ], + "max-statements-per-line": [ 0, { "max": 1 } ], + "multiline-comment-style": [ 0, "starred-block" ], + "multiline-ternary": [ 0, "always" ], + "new-cap": + [ 0, + { "newIsCap": true, "capIsNew": true, "properties": true } + ], + "new-parens": 0, + "newline-per-chained-call": [ 0, { "ignoreChainWithDepth": 2 } ], + "no-array-constructor": 0, + "@typescript-eslint/no-array-constructor": 0, + "no-bitwise": + [ 0, + { "allow": [ "~" ], "int32Hint": true } + ], + "no-continue": 0, + "no-inline-comments": 0, + "no-lonely-if": 0, + "no-mixed-operators": + [ 0, + { "groups": + [ [ "+", "-", "*", "/", "%", "**" ], + [ "&", "|", "^", "~", "<<", ">>", ">>>" ], + [ "==", "!=", "===", "!==", ">", ">=", "<", "<=" ], + [ "&&", "||" ], + [ "in", "instanceof" ] + ], + "allowSamePrecedence": true } + ], + "no-mixed-spaces-and-tabs": 1, + "no-multi-assign": 0, + "no-multiple-empty-lines": [ 0, { "max": 1 } ], + "no-negated-condition": 0, + "no-nested-ternary": 0, + "no-new-object": 0, + "no-plusplus": [ 0, { "allowForLoopAfterthoughts": true } ], + "no-restricted-syntax": 0, + "no-tabs": 0, + "no-ternary": 0, + "no-trailing-spaces": + [ 0, + { "skipBlankLines": false, "ignoreComments": false } + ], + "no-underscore-dangle": [ 0, { "allow": [ ] } ], + "no-unneeded-ternary": [ 0, { "defaultAssignment": true } ], + "no-whitespace-before-property": 0, + "nonblock-statement-body-position": [ 0, "beside" ], + "object-curly-newline": [ 0, { "multiline": true } ], + "object-curly-spacing": 0, + "@typescript-eslint/object-curly-spacing": 0, + "one-var": [ 0, "always" ], + "one-var-declaration-per-line": [ 0, "initializations" ], + "operator-assignment": [ 0, "always" ], + "operator-linebreak": 0, + "padded-blocks": [ 0, "always" ], + "padding-line-between-statements": 0, + "@typescript-eslint/padding-line-between-statements": 0, + "quote-props": [ 0, "always" ], + "quotes": 0, + "@typescript-eslint/quotes": [ 0, "double" ], + "require-jsdoc": + [ 0, + { "require": + { "FunctionDeclaration": true, + "MethodDefinition": false, + "ClassDeclaration": false, + "ArrowFunctionExpression": false, + "FunctionExpression": false } } + ], + "semi": 0, + "@typescript-eslint/semi": [ 0, "always" ], + "semi-spacing": [ 0, { "before": false, "after": true } ], + "semi-style": [ 0, "last" ], + "sort-keys": [ 0, "asc" ], + "sort-vars": [ 0, { "ignoreCase": true } ], + "space-before-blocks": [ 0, "always" ], + "space-before-function-paren": 0, + "@typescript-eslint/space-before-function-paren": [ 0, "always" ], + "space-in-parens": [ 0, "never" ], + "space-infix-ops": 0, + "@typescript-eslint/space-infix-ops": [ 0, { "int32Hint": false } ], + "space-unary-ops": [ 0, { "words": true, "nonwords": false } ], + "spaced-comment": [ 0, "always" ], + "switch-colon-spacing": [ 0, { "after": true, "before": false } ], + "template-tag-spacing": [ 0, "never" ], + "unicode-bom": [ 0, "never" ], + "wrap-regex": 0, + "arrow-body-style": [ 0, "as-needed" ], + "arrow-parens": [ 0, "always" ], + "arrow-spacing": [ 0, { "before": true, "after": true } ], + "constructor-super": 1, + "generator-star-spacing": [ 0, { "before": true, "after": false } ], + "no-confusing-arrow": [ 0, { "allowParens": false } ], + "no-class-assign": 1, + "no-const-assign": 1, + "no-dupe-class-members": 0, + "@typescript-eslint/no-dupe-class-members": 1, + "no-duplicate-imports": 0, + "@typescript-eslint/no-duplicate-imports": [ 0, { "includeExports": false } ], + "no-new-symbol": 1, + "no-restricted-imports": 0, + "@typescript-eslint/no-restricted-imports": [ 0, + { "paths": [ "exampleImport1", "exampleImport2" ] } + ], + "no-this-before-super": 1, + "no-useless-computed-key": 0, + "no-useless-rename": + [ 0, + { "ignoreDestructing": false, + "ignoreImport": false, + "ignoreExport": false } + ], + "no-var": 0, + "object-shorthand": [ 0, "always" ], + "prefer-arrow-callback": + [ 0, + { "allowNamedFunction": false, "allowUnboundThis": true } + ], + "prefer-const": + [ 0, + { "destructing": "any", "ignoreReadBeforeAssign": false } + ], + "prefer-destructing": + [ 0, + [ { "array": true, "object": true }, + { "enforceForRenamedProperties": false }] + ], + "prefer-numeric-literals": 0, + "prefer-rest-params": 0, + "prefer-spread": 0, + "prefer-template": 0, + "require-yield": 1, + "rest-spread-spacing": [ 0, "never" ], + "sort-imports": + [ 0, + { "ignoreCase": false, + "ignoreMemberSort": false, + "memberSyntaxSortOrder": [ "none", "all", "multiple", "single" ] } + ], + "symbol-description": 0, + "template-curly-spacing": [ 0, "never" ], + "yield-star-spacing": [ 0, { "before": true, "after": false } ], + "@typescript-eslint/adjacent-overload-signatures": 1, + "@typescript-eslint/array-type": [1, { + "array-type": [true, "generic"] + }], + "@typescript-eslint/await-thenable": 1, + "@typescript-eslint/ban-ts-comment": 1, + "@typescript-eslint/ban-tslint-comment": 0, + "@typescript-eslint/ban-types": 1, + "@typescript-eslint/class-literal-property-style": 0, + "@typescript-eslint/consistent-indexed-object-style": 0, + "@typescript-eslint/consistent-type-assertions": 0, + "@typescript-eslint/consistent-type-definitions": 0, + "@typescript-eslint/consistent-type-imports": 0, + "@typescript-eslint/explicit-function-return-type": 0, + "@typescript-eslint/explicit-member-accessibility": 0, + "@typescript-eslint/explicit-module-boundary-types": 0, + "@typescript-eslint/member-delimiter-style": 0, + "@typescript-eslint/member-ordering": 0, + "@typescript-eslint/method-signature-style": 0, + "@typescript-eslint/naming-convention": 0, + "@typescript-eslint/no-base-to-string": 0, + "@typescript-eslint/no-confusing-non-null-assertion": 0, + "@typescript-eslint/no-confusing-void-expression": 0, + "@typescript-eslint/no-dynamic-delete": 0, + "@typescript-eslint/no-empty-interface": 1, + "@typescript-eslint/no-explicit-any": 1, + "@typescript-eslint/no-extra-non-null-assertion": 1, + "@typescript-eslint/no-extraneous-class": 0, + "@typescript-eslint/no-floating-promises": 1, + "@typescript-eslint/no-for-in-array": 1, + "@typescript-eslint/no-implicit-any-catch": 1, + "@typescript-eslint/no-inferrable-types": 0, + "@typescript-eslint/no-invalid-void-type": 0, + "@typescript-eslint/no-meaningless-void-operator": 0, + "@typescript-eslint/no-misused-new": 1, + "@typescript-eslint/no-misused-promises": 1, + "@typescript-eslint/no-namespace": 1, + "@typescript-eslint/no-non-null-asserted-nullish-coalescing": 1, + "@typescript-eslint/no-non-null-asserted-optional-chain": 1, + "@typescript-eslint/no-non-null-assertion": 0, + "@typescript-eslint/no-parameter-properties": 0, + "@typescript-eslint/no-require-imports": 0, + "@typescript-eslint/no-this-alias": 1, + "@typescript-eslint/no-type-alias": 0, + "@typescript-eslint/no-unnecessary-boolean-literal-compare": 0, + "@typescript-eslint/no-unnecessary-condition": 0, + "@typescript-eslint/no-unnecessary-qualifier": 0, + "@typescript-eslint/no-unnecessary-type-arguments": 1, + "@typescript-eslint/no-unnecessary-type-assertion": 1, + "@typescript-eslint/no-unnecessary-type-constraint": 1, + "@typescript-eslint/no-unsafe-argument": 1, + "@typescript-eslint/no-unsafe-assignment": 1, + "@typescript-eslint/no-unsafe-call": 1, + "@typescript-eslint/no-unsafe-member-access": 1, + "@typescript-eslint/no-unsafe-return": 1, + "@typescript-eslint/no-var-requires": 1, + "@typescript-eslint/non-nullable-type-assertion-style": 0, + "@typescript-eslint/prefer-as-const": 1, + "@typescript-eslint/prefer-enum-initializers": 0, + "@typescript-eslint/prefer-for-of": 0, + "@typescript-eslint/prefer-function-type": 0, + "@typescript-eslint/prefer-includes": 0, + "@typescript-eslint/prefer-literal-enum-member": 0, + "@typescript-eslint/prefer-namespace-keyword": 1, + "@typescript-eslint/prefer-nullish-coalescing": 0, + "@typescript-eslint/prefer-optional-chain": 0, + "@typescript-eslint/prefer-readonly": 0, + "@typescript-eslint/prefer-readonly-parameter-types": 0, + "@typescript-eslint/prefer-reduce-type-parameter": 0, + "@typescript-eslint/prefer-regexp-exec": 0, + "@typescript-eslint/prefer-return-this-type": 0, + "@typescript-eslint/prefer-string-starts-ends-with": 0, + "@typescript-eslint/prefer-ts-expect-error": 0, + "@typescript-eslint/promise-function-async": 0, + "@typescript-eslint/require-array-sort-compare": 0, + "@typescript-eslint/restrict-plus-operands": 1, + "@typescript-eslint/restrict-template-expressions": 0, + "@typescript-eslint/sort-type-union-intersection-members": 0, + "@typescript-eslint/strict-boolean-expressions": 0, + "@typescript-eslint/switch-exhaustiveness-check": 0, + "@typescript-eslint/triple-slash-reference": 1, + "@typescript-eslint/type-annotation-spacing": 0, + "@typescript-eslint/typedef": 0, + "@typescript-eslint/unbound-method": 1, + "@typescript-eslint/unified-signatures": 0 +} diff --git a/javascript/cl/ESLintRunner/webpack.common.js b/javascript/cl/ESLintRunner/webpack.common.js new file mode 100644 index 0000000..3a68fe7 --- /dev/null +++ b/javascript/cl/ESLintRunner/webpack.common.js @@ -0,0 +1,48 @@ +const path = require('path'); +const CopyPlugin = require('copy-webpack-plugin'); +const webpack = require('webpack'); +const nodeExternals = require('webpack-node-externals'); + +module.exports = { + target: "node", + externals: [nodeExternals()], + externalsPresets:{ + node:true + }, + node: { + __dirname: false, + }, + entry: { + ESLintRunner:"./ESLintRunner.js" + }, + output: { + filename: '[name].js', + path: path.resolve(__dirname, "dist"), + clean: true, + }, + optimization: { + usedExports: 'global', + }, + + module: { + rules: [ + { + test: /\.node$/, + loader: "node-loader", + exclude: /"node_modules"/, + options: { + name: "[name].[ext]" + } + } + ] + }, + + plugins: [ + new webpack.BannerPlugin({ + banner: 'fullhash:[fullhash], chunkhash:[chunkhash], name:[name], base:[base], query:[query], file:[file]', + }), + new CopyPlugin({ + patterns: [{from: 'typescript-eslint.json'}], + }), + ] +} diff --git a/javascript/cl/ESLintRunner/webpack.dev.js b/javascript/cl/ESLintRunner/webpack.dev.js new file mode 100644 index 0000000..71640d1 --- /dev/null +++ b/javascript/cl/ESLintRunner/webpack.dev.js @@ -0,0 +1,8 @@ +const common = require('./webpack.common'); +const webpackMerge = require('webpack-merge'); + + +module.exports = webpackMerge.merge(common, { + mode: "development", + //devtool: "none", +}); \ No newline at end of file diff --git a/javascript/cl/ESLintRunner/webpack.prod.js b/javascript/cl/ESLintRunner/webpack.prod.js new file mode 100644 index 0000000..ffe330d --- /dev/null +++ b/javascript/cl/ESLintRunner/webpack.prod.js @@ -0,0 +1,10 @@ +const common = require('./webpack.common'); +const webpackMerge = require('webpack-merge'); +const CleanWebpackPlugin = require('clean-webpack-plugin').CleanWebpackPlugin; + +module.exports = webpackMerge.merge(common, { + mode: "production", + plugins: [ + new CleanWebpackPlugin() + ] +}); diff --git a/javascript/cl/JSAN/.gitignore b/javascript/cl/JSAN/.gitignore index 7e087fe..d1d0365 100644 --- a/javascript/cl/JSAN/.gitignore +++ b/javascript/cl/JSAN/.gitignore @@ -1,2 +1,4 @@ .idea/ node_modules +dist +build diff --git a/javascript/cl/JSAN/CMakeLists.txt b/javascript/cl/JSAN/CMakeLists.txt index b426c35..9f7d53f 100644 --- a/javascript/cl/JSAN/CMakeLists.txt +++ b/javascript/cl/JSAN/CMakeLists.txt @@ -1,17 +1,35 @@ set (PROGRAM_NAME JSAN) add_custom_target ( - ${PROGRAM_NAME} - COMMAND npm install ${MSVS_VERSION} > ${CMAKE_CURRENT_BINARY_DIR}/${PROGRAM_NAME}-build.log 2>&1 + ${PROGRAM_NAME}_install + COMMAND npm install ${MSVS_VERSION} > ${CMAKE_CURRENT_BINARY_DIR}/${PROGRAM_NAME}-npm-install.log 2>&1 DEPENDS javascriptAddon - WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}/node_modules/jsan + WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}/tmp_jsan ) -add_custom_copy_target(${PROGRAM_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/JSAN.js ${EXECUTABLE_OUTPUT_PATH}/node_modules/jsan/JSAN.js) -add_custom_copy_target(${PROGRAM_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/package.json ${EXECUTABLE_OUTPUT_PATH}/node_modules/jsan/package.json) -add_custom_copy_target(${PROGRAM_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/src ${EXECUTABLE_OUTPUT_PATH}/node_modules/jsan/src DIRECTORY) +add_custom_copy_target(${PROGRAM_NAME}_install ${CMAKE_CURRENT_SOURCE_DIR} ${EXECUTABLE_OUTPUT_PATH}/tmp_jsan DIRECTORY) +add_custom_generated_copy_dependency (${PROGRAM_NAME}_install ${EXECUTABLE_OUTPUT_PATH} ${EXECUTABLE_OUTPUT_PATH}/tmp_jsan javascriptAddon.node) -add_custom_generated_copy_dependency (${PROGRAM_NAME} ${EXECUTABLE_OUTPUT_PATH} ${EXECUTABLE_OUTPUT_PATH}/node_modules/jsan/ javascriptAddon.node) +set_target_properties (${PROGRAM_NAME}_install PROPERTIES FOLDER ${CMAKE_SUPPORT_FOLDER_NAME}) -set_visual_studio_project_folder(${PROGRAM_NAME} TRUE) +add_custom_target ( + ${PROGRAM_NAME}_build + COMMAND npm run build -- --no-color -o ${EXECUTABLE_OUTPUT_PATH}/node_modules/jsan > ${CMAKE_CURRENT_BINARY_DIR}/${PROGRAM_NAME}-npm-build.log 2>&1 + DEPENDS ${PROGRAM_NAME}_install + WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}/tmp_jsan +) + +set_target_properties (${PROGRAM_NAME}_build PROPERTIES FOLDER ${CMAKE_SUPPORT_FOLDER_NAME}) + +add_custom_target ( + ${PROGRAM_NAME}_virtual_target + # from cmake 3.17 + # COMMAND ${CMAKE_COMMAND} -E rm -rf ${EXECUTABLE_OUTPUT_PATH}/tmp_jsan + # until cmake 3.16 + COMMAND ${CMAKE_COMMAND} -E remove_directory -rf ${EXECUTABLE_OUTPUT_PATH}/tmp_jsan + DEPENDS ${PROGRAM_NAME}_build +) + +add_custom_generated_copy_dependency (${PROGRAM_NAME}_virtual_target ${EXECUTABLE_OUTPUT_PATH} ${EXECUTABLE_OUTPUT_PATH}/node_modules/jsan/ javascriptAddon.node) +set_visual_studio_project_folder(${PROGRAM_NAME}_virtual_target TRUE) diff --git a/javascript/cl/JSAN/package-lock.json b/javascript/cl/JSAN/package-lock.json new file mode 100644 index 0000000..c53c5c7 --- /dev/null +++ b/javascript/cl/JSAN/package-lock.json @@ -0,0 +1,2485 @@ +{ + "name": "jsan", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "requires": { + "@babel/highlight": "^7.14.5" + } + }, + "@babel/compat-data": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.7.tgz", + "integrity": "sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw==" + }, + "@babel/core": { + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.14.6.tgz", + "integrity": "sha512-gJnOEWSqTk96qG5BoIrl5bVtc23DCycmIePPYnamY9RboYdI4nFy5vAQMSl81O5K/W0sLDWfGysnOECC+KUUCA==", + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.14.5", + "@babel/helper-compilation-targets": "^7.14.5", + "@babel/helper-module-transforms": "^7.14.5", + "@babel/helpers": "^7.14.6", + "@babel/parser": "^7.14.6", + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0", + "source-map": "^0.5.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "@babel/generator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.5.tgz", + "integrity": "sha512-y3rlP+/G25OIX3mYKKIOlQRcqj7YgrvHxOLbVmyLJ9bPmi5ttvUmpydVjcFjZphOktWuA7ovbx91ECloWTfjIA==", + "requires": { + "@babel/types": "^7.14.5", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "@babel/helper-compilation-targets": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.14.5.tgz", + "integrity": "sha512-v+QtZqXEiOnpO6EYvlImB6zCD2Lel06RzOPzmkz/D/XgQiUu3C/Jb1LOqSt/AIA34TYi/Q+KlT8vTQrgdxkbLw==", + "requires": { + "@babel/compat-data": "^7.14.5", + "@babel/helper-validator-option": "^7.14.5", + "browserslist": "^4.16.6", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@babel/helper-function-name": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", + "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", + "requires": { + "@babel/helper-get-function-arity": "^7.14.5", + "@babel/template": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", + "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz", + "integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.14.7.tgz", + "integrity": "sha512-TMUt4xKxJn6ccjcOW7c4hlwyJArizskAhoSTOCkA0uZ+KghIaci0Qg9R043kUMWI9mtQfgny+NQ5QATnZ+paaA==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-module-imports": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz", + "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-module-transforms": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.14.5.tgz", + "integrity": "sha512-iXpX4KW8LVODuAieD7MzhNjmM6dzYY5tfRqT+R9HDXWl0jPn/djKmA+G9s/2C2T9zggw5tK1QNqZ70USfedOwA==", + "requires": { + "@babel/helper-module-imports": "^7.14.5", + "@babel/helper-replace-supers": "^7.14.5", + "@babel/helper-simple-access": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/helper-validator-identifier": "^7.14.5", + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz", + "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", + "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==" + }, + "@babel/helper-replace-supers": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.14.5.tgz", + "integrity": "sha512-3i1Qe9/8x/hCHINujn+iuHy+mMRLoc77b2nI9TB0zjH1hvn9qGlXjWlggdwUcju36PkPCy/lpM7LLUdcTyH4Ow==", + "requires": { + "@babel/helper-member-expression-to-functions": "^7.14.5", + "@babel/helper-optimise-call-expression": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-simple-access": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.5.tgz", + "integrity": "sha512-nfBN9xvmCt6nrMZjfhkl7i0oTV3yxR4/FztsbOASyTvVcoYd0TRHh7eMLdlEcCqobydC0LAF3LtC92Iwxo0wyw==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", + "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==" + }, + "@babel/helper-validator-option": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", + "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==" + }, + "@babel/helpers": { + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.6.tgz", + "integrity": "sha512-yesp1ENQBiLI+iYHSJdoZKUtRpfTlL1grDIX9NRlAVppljLw/4tTyYupIB7uIYmC3stW/imAv8EqaKaS/ibmeA==", + "requires": { + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "requires": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.7.tgz", + "integrity": "sha512-X67Z5y+VBJuHB/RjwECp8kSl5uYi0BvRbNeWqkaJCVh+LiTPl19WBUfG627psSgp9rSf6ojuXghQM3ha6qHHdA==" + }, + "@babel/plugin-syntax-flow": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.14.5.tgz", + "integrity": "sha512-9WK5ZwKCdWHxVuU13XNT6X73FGmutAXeor5lGFq6qhOFtMFUF4jkbijuyUdZZlpYq6E2hZeZf/u3959X9wsv0Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-flow-strip-types": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.14.5.tgz", + "integrity": "sha512-KhcolBKfXbvjwI3TV7r7TkYm8oNXHNBqGOy6JDVwtecFaRoKYsUUqJdS10q0YDKW1c6aZQgO+Ys3LfGkox8pXA==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-flow": "^7.14.5" + } + }, + "@babel/preset-flow": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.14.5.tgz", + "integrity": "sha512-pP5QEb4qRUSVGzzKx9xqRuHUrM/jEzMqdrZpdMA+oUCRgd5zM1qGr5y5+ZgAL/1tVv1H0dyk5t4SKJntqyiVtg==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-validator-option": "^7.14.5", + "@babel/plugin-transform-flow-strip-types": "^7.14.5" + } + }, + "@babel/template": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", + "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==", + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/parser": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/traverse": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.7.tgz", + "integrity": "sha512-9vDr5NzHu27wgwejuKL7kIOm4bwEtaPQ4Z6cpCmjSuaRqpH/7xc4qcGEscwMqlkwgcXl6MvqoAjZkQ24uSdIZQ==", + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.14.5", + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-hoist-variables": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/parser": "^7.14.7", + "@babel/types": "^7.14.5", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz", + "integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==", + "requires": { + "@babel/helper-validator-identifier": "^7.14.5", + "to-fast-properties": "^2.0.0" + } + }, + "@discoveryjs/json-ext": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.3.tgz", + "integrity": "sha512-Fxt+AfXgjMoin2maPIYzFZnQjAXjAL0PHscM5pRTtatFqB+vZxAM9tLp2Optnuw3QOQC40jTNeGYFOMvyf7v9g==", + "dev": true + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" + }, + "@nodelib/fs.walk": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.7.tgz", + "integrity": "sha512-BTIhocbPBSrRmHxOAJFtR18oLhxTtAFDAvL8hY1S3iU8k+E60W/YFs4jrixGzQjMpF4qPXxIQHcjVD9dz1C2QA==", + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@types/eslint": { + "version": "7.2.13", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.13.tgz", + "integrity": "sha512-LKmQCWAlnVHvvXq4oasNUMTJJb2GwSyTY8+1C7OH5ILR8mPLaljv1jxL1bXW3xB3jFbQxTKxJAvI8PyjB09aBg==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.0.tgz", + "integrity": "sha512-O/ql2+rrCUe2W2rs7wMR+GqPRcgB6UiqN5RhrR5xruFlY7l9YLMn0ZkDzjoHLeiFkR8MCQZVudUuuvQ2BLC9Qw==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "0.0.46", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.46.tgz", + "integrity": "sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==" + }, + "@types/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/json-schema": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", + "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "dev": true + }, + "@types/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==" + }, + "@types/node": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.0.0.tgz", + "integrity": "sha512-TmCW5HoZ2o2/z2EYi109jLqIaPIi9y/lc2LmDCWzuCi35bcaQ+OtUh6nwBiFK7SOu25FAU5+YKdqFZUwtqGSdg==" + }, + "@typescript-eslint/scope-manager": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.28.2.tgz", + "integrity": "sha512-MqbypNjIkJFEFuOwPWNDjq0nqXAKZvDNNs9yNseoGBB1wYfz1G0WHC2AVOy4XD7di3KCcW3+nhZyN6zruqmp2A==", + "requires": { + "@typescript-eslint/types": "4.28.2", + "@typescript-eslint/visitor-keys": "4.28.2" + } + }, + "@typescript-eslint/types": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.28.2.tgz", + "integrity": "sha512-Gr15fuQVd93uD9zzxbApz3wf7ua3yk4ZujABZlZhaxxKY8ojo448u7XTm/+ETpy0V0dlMtj6t4VdDvdc0JmUhA==" + }, + "@typescript-eslint/typescript-estree": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.2.tgz", + "integrity": "sha512-86lLstLvK6QjNZjMoYUBMMsULFw0hPHJlk1fzhAVoNjDBuPVxiwvGuPQq3fsBMCxuDJwmX87tM/AXoadhHRljg==", + "requires": { + "@typescript-eslint/types": "4.28.2", + "@typescript-eslint/visitor-keys": "4.28.2", + "debug": "^4.3.1", + "globby": "^11.0.3", + "is-glob": "^4.0.1", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.2.tgz", + "integrity": "sha512-aT2B4PLyyRDUVUafXzpZFoc0C9t0za4BJAKP5sgWIhG+jHECQZUEjuQSCIwZdiJJ4w4cgu5r3Kh20SOdtEBl0w==", + "requires": { + "@typescript-eslint/types": "4.28.2", + "eslint-visitor-keys": "^2.0.0" + } + }, + "@webassemblyjs/ast": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.0.tgz", + "integrity": "sha512-kX2W49LWsbthrmIRMbQZuQDhGtjyqXfEmmHyEi4XWnSZtPmxY0+3anPIzsnRb45VH/J55zlOfWvZuY47aJZTJg==", + "dev": true, + "requires": { + "@webassemblyjs/helper-numbers": "1.11.0", + "@webassemblyjs/helper-wasm-bytecode": "1.11.0" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.0.tgz", + "integrity": "sha512-Q/aVYs/VnPDVYvsCBL/gSgwmfjeCb4LW8+TMrO3cSzJImgv8lxxEPM2JA5jMrivE7LSz3V+PFqtMbls3m1exDA==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.0.tgz", + "integrity": "sha512-baT/va95eXiXb2QflSx95QGT5ClzWpGaa8L7JnJbgzoYeaA27FCvuBXU758l+KXWRndEmUXjP0Q5fibhavIn8w==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.0.tgz", + "integrity": "sha512-u9HPBEl4DS+vA8qLQdEQ6N/eJQ7gT7aNvMIo8AAWvAl/xMrcOSiI2M0MAnMCy3jIFke7bEee/JwdX1nUpCtdyA==", + "dev": true + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.0.tgz", + "integrity": "sha512-DhRQKelIj01s5IgdsOJMKLppI+4zpmcMQ3XboFPLwCpSNH6Hqo1ritgHgD0nqHeSYqofA6aBN/NmXuGjM1jEfQ==", + "dev": true, + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.0", + "@webassemblyjs/helper-api-error": "1.11.0", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.0.tgz", + "integrity": "sha512-MbmhvxXExm542tWREgSFnOVo07fDpsBJg3sIl6fSp9xuu75eGz5lz31q7wTLffwL3Za7XNRCMZy210+tnsUSEA==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.0.tgz", + "integrity": "sha512-3Eb88hcbfY/FCukrg6i3EH8H2UsD7x8Vy47iVJrP967A9JGqgBVL9aH71SETPx1JrGsOUVLo0c7vMCN22ytJew==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/helper-buffer": "1.11.0", + "@webassemblyjs/helper-wasm-bytecode": "1.11.0", + "@webassemblyjs/wasm-gen": "1.11.0" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.0.tgz", + "integrity": "sha512-KXzOqpcYQwAfeQ6WbF6HXo+0udBNmw0iXDmEK5sFlmQdmND+tr773Ti8/5T/M6Tl/413ArSJErATd8In3B+WBA==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.0.tgz", + "integrity": "sha512-aqbsHa1mSQAbeeNcl38un6qVY++hh8OpCOzxhixSYgbRfNWcxJNJQwe2rezK9XEcssJbbWIkblaJRwGMS9zp+g==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.0.tgz", + "integrity": "sha512-A/lclGxH6SpSLSyFowMzO/+aDEPU4hvEiooCMXQPcQFPPJaYcPQNKGOCLUySJsYJ4trbpr+Fs08n4jelkVTGVw==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.0.tgz", + "integrity": "sha512-JHQ0damXy0G6J9ucyKVXO2j08JVJ2ntkdJlq1UTiUrIgfGMmA7Ik5VdC/L8hBK46kVJgujkBIoMtT8yVr+yVOQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/helper-buffer": "1.11.0", + "@webassemblyjs/helper-wasm-bytecode": "1.11.0", + "@webassemblyjs/helper-wasm-section": "1.11.0", + "@webassemblyjs/wasm-gen": "1.11.0", + "@webassemblyjs/wasm-opt": "1.11.0", + "@webassemblyjs/wasm-parser": "1.11.0", + "@webassemblyjs/wast-printer": "1.11.0" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.0.tgz", + "integrity": "sha512-BEUv1aj0WptCZ9kIS30th5ILASUnAPEvE3tVMTrItnZRT9tXCLW2LEXT8ezLw59rqPP9klh9LPmpU+WmRQmCPQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/helper-wasm-bytecode": "1.11.0", + "@webassemblyjs/ieee754": "1.11.0", + "@webassemblyjs/leb128": "1.11.0", + "@webassemblyjs/utf8": "1.11.0" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.0.tgz", + "integrity": "sha512-tHUSP5F4ywyh3hZ0+fDQuWxKx3mJiPeFufg+9gwTpYp324mPCQgnuVKwzLTZVqj0duRDovnPaZqDwoyhIO8kYg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/helper-buffer": "1.11.0", + "@webassemblyjs/wasm-gen": "1.11.0", + "@webassemblyjs/wasm-parser": "1.11.0" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.0.tgz", + "integrity": "sha512-6L285Sgu9gphrcpDXINvm0M9BskznnzJTE7gYkjDbxET28shDqp27wpruyx3C2S/dvEwiigBwLA1cz7lNUi0kw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/helper-api-error": "1.11.0", + "@webassemblyjs/helper-wasm-bytecode": "1.11.0", + "@webassemblyjs/ieee754": "1.11.0", + "@webassemblyjs/leb128": "1.11.0", + "@webassemblyjs/utf8": "1.11.0" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.0.tgz", + "integrity": "sha512-Fg5OX46pRdTgB7rKIUojkh9vXaVN6sGYCnEiJN1GYkb0RPwShZXp6KTDqmoMdQPKhcroOXh3fEzmkWmCYaKYhQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.0", + "@xtuc/long": "4.2.2" + } + }, + "@webpack-cli/configtest": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.0.4.tgz", + "integrity": "sha512-cs3XLy+UcxiP6bj0A6u7MLLuwdXJ1c3Dtc0RkKg+wiI1g/Ti1om8+/2hc2A2B60NbBNAbMgyBMHvyymWm/j4wQ==", + "dev": true + }, + "@webpack-cli/info": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.3.0.tgz", + "integrity": "sha512-ASiVB3t9LOKHs5DyVUcxpraBXDOKubYu/ihHhU+t1UPpxsivg6Od2E2qU4gJCekfEddzRBzHhzA/Acyw/mlK/w==", + "dev": true, + "requires": { + "envinfo": "^7.7.3" + } + }, + "@webpack-cli/serve": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.5.1.tgz", + "integrity": "sha512-4vSVUiOPJLmr45S8rMGy7WDvpWxfFxfP/Qx/cxZFCfvoypTYpPPL1X8VIZMe0WTA+Jr7blUxwUSEZNkjoMTgSw==", + "dev": true + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "acorn": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.4.1.tgz", + "integrity": "sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==" + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, + "babel-core": { + "version": "6.26.3", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", + "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", + "requires": { + "babel-code-frame": "^6.26.0", + "babel-generator": "^6.26.0", + "babel-helpers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-register": "^6.26.0", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "convert-source-map": "^1.5.1", + "debug": "^2.6.9", + "json5": "^0.5.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.4", + "path-is-absolute": "^1.0.1", + "private": "^0.1.8", + "slash": "^1.0.0", + "source-map": "^0.5.7" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "babel-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "requires": { + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", + "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "requires": { + "babel-core": "^6.26.0", + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "home-or-tmp": "^2.0.0", + "lodash": "^4.17.4", + "mkdirp": "^0.5.1", + "source-map-support": "^0.4.15" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "requires": { + "source-map": "^0.5.6" + } + } + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "requires": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "requires": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + }, + "dependencies": { + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" + } + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.16.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", + "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "requires": { + "caniuse-lite": "^1.0.30001219", + "colorette": "^1.2.2", + "electron-to-chromium": "^1.3.723", + "escalade": "^3.1.1", + "node-releases": "^1.1.71" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001242", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001242.tgz", + "integrity": "sha512-KvNuZ/duufelMB3w2xtf9gEWCSxJwUgoxOx5b6ScLXC4kPc9xsczUVCPrQU26j5kOsHM4pSUL54tAZt5THQKug==" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true + }, + "clean-webpack-plugin": { + "version": "4.0.0-alpha.0", + "resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-4.0.0-alpha.0.tgz", + "integrity": "sha512-+X6mASBbGSVyw8L9/1rhQ+vS4uaQMopf194kX7Aes8qfezgCFL+qv5W0nwP3a0Tud5kUckARk8tFcoyOSKEjhg==", + "requires": { + "del": "^4.1.1" + } + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" + }, + "command-line-args": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.1.1.tgz", + "integrity": "sha512-hL/eG8lrll1Qy1ezvkant+trihbGnaKaeEjj6Scyr3DN+RC7iQ5Rz84IeLERfAWDGo0HBSNAakczwgCilDXnWg==", + "requires": { + "array-back": "^3.0.1", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + } + }, + "command-line-usage": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.1.tgz", + "integrity": "sha512-F59pEuAR9o1SF/bD0dQBDluhpT4jJQNWUHEuVBqpDmCUo6gPjCi+m9fCWnWZVR/oG6cMTUms4h+3NPl74wGXvA==", + "requires": { + "array-back": "^4.0.1", + "chalk": "^2.4.2", + "table-layout": "^1.0.1", + "typical": "^5.2.0" + }, + "dependencies": { + "array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==" + }, + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" + } + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "requires": { + "safe-buffer": "~5.1.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "requires": { + "ms": "2.1.2" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "requires": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + }, + "dependencies": { + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "requires": { + "array-uniq": "^1.0.1" + } + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } + } + } + } + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "requires": { + "repeating": "^2.0.0" + } + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "requires": { + "path-type": "^4.0.0" + } + }, + "dom-serializer": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" + }, + "domhandler": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz", + "integrity": "sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==", + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.7.0.tgz", + "integrity": "sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "electron-to-chromium": { + "version": "1.3.766", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.766.tgz", + "integrity": "sha512-u2quJ862q9reRKh/je3GXis3w38+RoXH1J9N3XjtsS6NzmUAosNsyZgUVFZPN/ZlJ3v6T0rTyZR3q/J5c6Sy5w==" + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, + "enhanced-resolve": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.2.tgz", + "integrity": "sha512-F27oB3WuHDzvR2DOGNTaYy0D5o0cnrv8TeI482VM4kYgQd/FT9lUQwuNsJ0oOHtBUq7eiW5ytqzp7nBFknL+GA==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + }, + "envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "dev": true + }, + "es-module-lexer": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.6.0.tgz", + "integrity": "sha512-f8kcHX1ArhllUtb/wVSyvygoKCznIjnxhLxy7TCvIiMdT7fL4ZDTIKaadMe6eLvOXg6Wk02UeoFgUoZ2EKZZUA==", + "dev": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "dependencies": { + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==" + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" + }, + "estree-util-attach-comments": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-2.0.0.tgz", + "integrity": "sha512-kT9YVRvlt2ewPp9BazfIIgXMGsXOEpOm57bK8aa4F3eOEndMml2JAETjWaG3SZYHmC6axSNIzHGY718dYwIuVg==", + "requires": { + "@types/estree": "^0.0.46" + } + }, + "estree-walker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.0.tgz", + "integrity": "sha512-s6ceX0NFiU/vKPiKvFdR83U1Zffu7upwZsGwpoqfg5rbbq1l50WQ5hCeIvM6E6oD4shUHCYMsiFPns4Jk0YfMQ==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.6.tgz", + "integrity": "sha512-GnLuqj/pvQ7pX8/L4J84nijv6sAnlwvSDpMkJi9i7nPmPxGtRPkBSStfvDW5l6nMdX9VWe+pkKWFTgD+vF2QSQ==", + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fastest-levenshtein": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", + "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", + "dev": true + }, + "fastq": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.1.tgz", + "integrity": "sha512-HOnr8Mc60eNYl1gzwp6r5RoUyAn5/glBolUzP/Ez6IFVPMPirxn/9phgL6zhOtaTy7ISwPvQ+wT+hfcRZh/bzw==", + "requires": { + "reusify": "^1.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "requires": { + "array-back": "^3.0.1" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "git-revision-webpack-plugin": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/git-revision-webpack-plugin/-/git-revision-webpack-plugin-5.0.0.tgz", + "integrity": "sha512-RptQN/4UKcEPkCBmRy8kLPo5i8MnF8+XfAgFYN9gbwmKLTLx4YHsQw726H+C5+sIGDixDkmGL3IxPA2gKo+u4w==", + "dev": true + }, + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "globby": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", + "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "hashmap": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/hashmap/-/hashmap-2.4.0.tgz", + "integrity": "sha512-Ngj48lhnxJdnBAEVbubKBJuN1elfVLZJs94ZixRi98X3GCU4v6pgj9qRkHt6H8WaVJ69Wv0r1GhtS7hvF9zCgg==" + }, + "home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.1" + } + }, + "htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==" + }, + "import-local": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", + "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "dev": true + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "^1.0.0" + } + }, + "is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==" + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==" + }, + "is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "requires": { + "is-path-inside": "^2.1.0" + } + }, + "is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "requires": { + "path-is-inside": "^1.0.2" + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "jest-worker": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.0.6.tgz", + "integrity": "sha512-qupxcj/dRuA3xHPMUd40gr2EaAurFbkwzOh7wfPaeE9id7hyjURRQoqNfHifHK3XjJU6YJJUQKILGUnwGPEOCA==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "jscg": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/jscg/-/jscg-2.0.6.tgz", + "integrity": "sha512-G4Dpdyw7SZbrnRwB+qZc4xfUE+W1ua4xEMuVb5XSWgc75UVk1dpOAWF+FXLQ/GQnI5BA8HXosFPbQsaIUvq2TA==", + "requires": { + "@babel/core": "^7.14.6", + "@babel/preset-flow": "^7.14.5", + "@typescript-eslint/typescript-estree": "^4.28.0", + "argparse": "^2.0.1", + "babel-core": "^6.26.3", + "typescript": "^4.3.4", + "underscore": "^1.13.1" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "requires": { + "minimist": "^1.2.5" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "loader-runner": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", + "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", + "dev": true + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "lru-cache-node": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lru-cache-node/-/lru-cache-node-1.0.1.tgz", + "integrity": "sha512-/OyyXZ2bVyYOH0670tdL7FTEKypf743+onohbq17qkV1dHQfg6CQabBKTg3BI1SF1bfgzLLNQg1JKow8KMy9aw==" + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "mime-db": { + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", + "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==", + "dev": true + }, + "mime-types": { + "version": "2.1.31", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", + "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", + "dev": true, + "requires": { + "mime-db": "1.48.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node-loader": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/node-loader/-/node-loader-2.0.0.tgz", + "integrity": "sha512-I5VN34NO4/5UYJaUBtkrODPWxbobrE4hgDqPrjB25yPkonFhCmZ146vTH+Zg417E9Iwoh1l/MbRs1apc5J295Q==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0" + } + }, + "node-releases": { + "version": "1.1.73", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", + "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==" + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + }, + "dependencies": { + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + } + } + }, + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==" + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "rechoir": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz", + "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==", + "dev": true, + "requires": { + "resolve": "^1.9.0" + } + }, + "reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==" + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "requires": { + "is-finite": "^1.0.0" + } + }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "schema-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.0.tgz", + "integrity": "sha512-tTEaeYkyIhEZ9uWgAjDerWov3T9MgX8dhhy2r0IGeeX4W8ngtGl1++dUve/RUqzuaASSh7shwCDJjEzthxki8w==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.7", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "sha1": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz", + "integrity": "sha1-rdqnqTFo85PxnrKxUJFhjicA+Eg=", + "requires": { + "charenc": ">= 0.0.1", + "crypt": ">= 0.0.1" + } + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "table-layout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", + "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", + "requires": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + }, + "dependencies": { + "array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==" + }, + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" + } + } + }, + "tapable": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", + "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==", + "dev": true + }, + "terser": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.1.tgz", + "integrity": "sha512-b3e+d5JbHAe/JSjwsC3Zn55wsBIM7AsHLjKxT31kGCldgbpFePaFo+PiddtO6uwRZWRw7sPXmAN8dTW61xmnSg==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.7.2", + "source-map-support": "~0.5.19" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, + "terser-webpack-plugin": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.1.4.tgz", + "integrity": "sha512-C2WkFwstHDhVEmsmlCxrXUtVklS+Ir1A7twrYzrDrQQOIMOaVAYykaoo/Aq1K0QRkMoY2hhvDQY1cm4jnIMFwA==", + "dev": true, + "requires": { + "jest-worker": "^27.0.2", + "p-limit": "^3.1.0", + "schema-utils": "^3.0.0", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1", + "terser": "^5.7.0" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "requires": { + "tslib": "^1.8.1" + } + }, + "typescript": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", + "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==" + }, + "typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==" + }, + "underscore": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", + "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==" + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "watchpack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz", + "integrity": "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==", + "dev": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "webpack": { + "version": "5.42.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.42.1.tgz", + "integrity": "sha512-msikozzXrG2Hdx+dElq0fyNvxPFsaM2dKLc/l+xkMmhO/1qwVJ9K9gY+fi/49MYWcpSP7alnK5Q78Evrd1LiqQ==", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.0", + "@types/estree": "^0.0.48", + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/wasm-edit": "1.11.0", + "@webassemblyjs/wasm-parser": "1.11.0", + "acorn": "^8.4.1", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.8.0", + "es-module-lexer": "^0.6.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.4", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.0.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.2.0", + "webpack-sources": "^2.3.0" + }, + "dependencies": { + "@types/estree": { + "version": "0.0.48", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.48.tgz", + "integrity": "sha512-LfZwXoGUDo0C3me81HXgkBg5CTQYb6xzEl+fNmbO4JdRiSKQ8A0GD1OBBvKAIsbCUgoyAty7m99GqqMQe784ew==", + "dev": true + } + } + }, + "webpack-cli": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.7.2.tgz", + "integrity": "sha512-mEoLmnmOIZQNiRl0ebnjzQ74Hk0iKS5SiEEnpq3dRezoyR3yPaeQZCMCe+db4524pj1Pd5ghZXjT41KLzIhSLw==", + "dev": true, + "requires": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.0.4", + "@webpack-cli/info": "^1.3.0", + "@webpack-cli/serve": "^1.5.1", + "colorette": "^1.2.1", + "commander": "^7.0.0", + "execa": "^5.0.0", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "v8-compile-cache": "^2.2.0", + "webpack-merge": "^5.7.3" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true + } + } + }, + "webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + } + }, + "webpack-sources": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.0.tgz", + "integrity": "sha512-WyOdtwSvOML1kbgtXbTDnEW0jkJ7hZr/bDByIwszhWd/4XX1A3XMkrbFMsuH4+/MfLlZCUzlAdg4r7jaGKEIgQ==", + "dev": true, + "requires": { + "source-list-map": "^2.0.1", + "source-map": "^0.6.1" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "wordwrapjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", + "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", + "requires": { + "reduce-flatten": "^2.0.0", + "typical": "^5.2.0" + }, + "dependencies": { + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/javascript/cl/JSAN/package.json b/javascript/cl/JSAN/package.json index 4dd7e22..e903231 100644 --- a/javascript/cl/JSAN/package.json +++ b/javascript/cl/JSAN/package.json @@ -2,23 +2,33 @@ "name": "jsan", "version": "1.0.0", "description": "JavaScript analyzer", - "main": "JSAN.js", + "main": "src/index.js", "private": true, "dependencies": { - "@persper/js-callgraph": "1.1.4", - "JSONStream": "1.3.5", - "command-line-args": "5.0.2", - "command-line-usage": "5.0.5", - "escope": "3.6.0", - "espree": "4.1.0", - "estraverse": "4.2.0", - "hashmap": "2.3.0", - "lodash.sortby": "4.7.0", + "@typescript-eslint/scope-manager": "^4.26.1", + "@typescript-eslint/typescript-estree": "^4.26.1", + "clean-webpack-plugin": "^4.0.0-alpha.0", + "command-line-args": "^5.1.1", + "command-line-usage": "^6.1.1", + "estree-util-attach-comments": "^2.0.0", + "estree-walker": "^3.0.0", + "hashmap": "^2.4.0", + "htmlparser2": "^6.1.0", + "jscg": "^2.0.6", + "lodash-es": "^4.17.21", "lru-cache-node": "^1.0.1", - "parse5": "5.1.0", - "sha1": "^1.1.1" + "sha1": "^1.1.1", + "typescript": "^4.3.2" }, "scripts": { - "analyze": "node JSAN.js" + "start": "webpack --config webpack.dev.js", + "build": "webpack --config webpack.prod.js" + }, + "devDependencies": { + "git-revision-webpack-plugin": "^5.0.0", + "node-loader": "^2.0.0", + "webpack": "^5.38.1", + "webpack-cli": "^4.7.0", + "webpack-merge": "^5.7.3" } } diff --git a/javascript/cl/JSAN/src/assets/crossRefSolver.js b/javascript/cl/JSAN/src/assets/crossRefSolver.js deleted file mode 100644 index ef1e0c5..0000000 --- a/javascript/cl/JSAN/src/assets/crossRefSolver.js +++ /dev/null @@ -1,246 +0,0 @@ -/* - * This file is part of OpenStaticAnalyzer. - * - * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged - * - * Licensed under Version 1.2 of the EUPL (the "Licence"); - * - * You may not use this work except in compliance with the Licence. - * - * You may obtain a copy of the Licence in the LICENSE file or at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ - -/* -* Module that solves the cross references of the given AST. -*/ -const estraverse = require('estraverse'); -const escope = require('escope'); -let globals = require('../globals'); -let scopeManager = null; -let scopeTree = null; -let currentScope = null; -let actNode = null; -let parsingOptions = null; - -/* - tree definition for cross reference -*/ -function Node(data) { - this.data = data; - this.parent = null; - this.children = []; -} - -function Tree(data) { - let node = new Node(data); - this._root = node; - - this.add = function (data, parent) { - let child = new Node(data); - child.parent = parent; - parent.children.push(child); - return child; - } -} - -function leave(node) { - if (/Function/.test(node.type) || /ClassDeclaration/.test(node.type)) { - if (currentScope !== null) { - currentScope = currentScope.upper; // set to parent scope - } - actNode = actNode.parent; - } -} - -function enter(ast, node) { - if (!scopeManager) { - scopeManager = escope.analyze(ast, parsingOptions); - } - if ("Program" === node.type) { - currentScope = scopeManager.acquire(ast); //global scope for that file - - scopeTree = new Tree({position: undefined, scope: currentScope, variables: []}); - actNode = scopeTree._root; - } else if (/Function/.test(node.type) || /ClassDeclaration/.test(node.type)) { - //add var to actNode - if (node.id && node.id.name) { - actNode.data.variables.push({name: node.id.name, node: node}); - } - - //new scope - currentScope = scopeManager.acquire(node); // get current function scope - actNode = scopeTree.add({position: node.range, scope: currentScope, variables: []}, actNode); - - //add function params to vars - if (/Function/.test(node.type)) { - let idsInAsParams = extractIdentifiersFromParams(node.params); - for (let i = 0; i < idsInAsParams.length; i++) { - actNode.data.variables.push({name: idsInAsParams[i].name, node: idsInAsParams[i]}); - } - } - } - else if (/VariableDeclarator/.test(node.type)) { - actNode.data.variables.push({name: node.id.name, node: node}); - } -} - -exports.setParsingOptions = function (parsingOptions) { - this.parsingOptions = parsingOptions; -}; - -exports.gatherScopes = function (ast, node, enterOrLeave) { - parsingOptions = this.parsingOptions; - if (enterOrLeave === "enter") { - enter(ast, node); - } - else if (enterOrLeave === "leave") { - leave(node); - } -}; - -exports.resolveNode = function (ast, filename, range_start, range_end, inner = false) { - const searchNode = { - file: filename, range: { - start: range_start, end: range_end - } - }; - let result = null; - let status = false; - - ast.forEach(astNode => { - if (status || astNode.filename !== searchNode.file) { - return; - } - globals.setActualFile(astNode.filename); - - // find the most inner node which has the same exact source position - estraverse.traverse(astNode, { - enter: function (node) { - if (status){ - if(inner){ // return the most inner node - if (node.range[0] !== searchNode.range.start || node.range[1] !== searchNode.range.end){ - return; - } - } - else{ // return the most outer node - return; - } - - } - if (node.range[0] === searchNode.range.start && node.range[1] === searchNode.range.end && node.type !== 'Program') { - status = true; - result = node; - } - } - }); - }); - return result; -}; - -exports.resolveVariableUsages = function (node, parent) { - - let skip = [ - "VariableDeclarator", - "Function" - ]; - if (/Identifier/.test(node.type)) { - //reference -> create a cross edge - if (skip.indexOf(parent.type) === -1) { - let referencedNode = getReferencedNode(node, scopeTree); - if (referencedNode !== null) { - if(referencedNode.range[0] === node.range[0] && referencedNode.range[1] === node.range[1]){ - return null; - } - - return { - source: { - label: node.name, - file: globals.getActualFile(), - start: {row: node.loc.start.line, column: node.loc.start.column}, - end: {row: node.loc.end.line, column: node.loc.end.column}, - range: {start: node.range[0], end: node.range[1]}, - node: node - }, - target: { - label: null, - file: globals.getActualFile(), - start: {row: referencedNode.loc.start.line, column: referencedNode.loc.start.column}, - end: {row: referencedNode.loc.end.line, column: referencedNode.loc.end.column}, - range: {start: referencedNode.range[0], end: referencedNode.range[1]}, - node: referencedNode - } - }; - } - } - } - return null; -}; - -function getReferencedNode(identifier, tree) { - let actNode = tree._root; - for (let i = 0; i < actNode.children.length; i++) { - //matching scope - if (actNode.children[i].data.position[0] <= identifier.range[0] && actNode.children[i].data.position[1] >= identifier.range[1]) { - i = 0; - actNode = actNode.children[i]; - } - } - - while (actNode !== null) { - for (let i = 0; i < actNode.data.variables.length; i++) { - if (actNode.data.variables[i].name === identifier.name) { - return actNode.data.variables[i].node; - } - } - - actNode = actNode.parent; - } - return null; -} - -function setRefersTo(identifier, referencedNode) { - if (identifier === referencedNode) { - return; - } - if (/VariableDeclarator/.test(referencedNode.type) || /Function/.test(referencedNode.type) || /Identifier/.test(referencedNode.type)) { - globals.getWrapperOfNode(identifier).setRefersTo(globals.getWrapperOfNode(referencedNode)); - } -} - -function extractIdentifiersFromParams(params) { - let identifiers = []; - for (let i = 0; i < params.length; i++) { - //in case of identifier - if (params[i].type === "Identifier" && params[i].name) { - identifiers.push(params[i]); - } - // - else if (params[i].type === "AssignmentPattern") { - //function f(x = 10, y = 20){} - if (params[i].left.type === "Identifier" && params[i].left.name) { - identifiers.push(params[i].left); - } - - //assignment is an array - //function f([x,y] = 10) - //function f([x,y] = [20,30]) - if (params[i].left.type === "ArrayPattern") { - for (let j = 0; j < params[i].left.elements.length; j++) { - if (params[i].left.elements[j].type === "Identifier") { - identifiers.push(params[i].left.elements[j]); - } - } - } - //TODO: objectPattern - } - } - return identifiers; -} diff --git a/javascript/cl/JSAN/src/assets/htmlExtractor.js b/javascript/cl/JSAN/src/assets/htmlExtractor.js index 5ad95cc..666a3db 100644 --- a/javascript/cl/JSAN/src/assets/htmlExtractor.js +++ b/javascript/cl/JSAN/src/assets/htmlExtractor.js @@ -18,9 +18,11 @@ * limitations under the Licence. */ -const fs = require('fs'); -const parse5 = require('parse5'); +import * as fs from "fs"; +import * as htmlparser2 from "htmlparser2"; +import {sortBy} from 'lodash-es'; +const JSEvents = ['onafterprint', 'onbeforeprint', 'onbeforeunload', 'onerror', 'onhashchange', 'onload', 'onmessage', 'onoffline', 'ononline', 'onpagehide', 'onpageshow', 'onpopstate', 'onresize', 'onstorage', 'onunload', 'onblur', 'onchange', 'oncontextmenu', 'onfocus', 'oninput', 'oninvalid', 'onreset', 'onsearch', 'onselect', 'onsubmit', 'onkeydown', 'onkeypress', 'onkeyup', 'onclick', 'ondblclick', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onwheel', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onscroll', 'oncopy', 'oncut', 'onpaste', 'onabort', 'oncanplay', 'oncanplaythrough', 'oncuechange', 'ondurationchange', 'onemptied', 'onended', 'onerror', 'onloadeddata', 'onloadedmetadata', 'onloadstart', 'onpause', 'onplay', 'onplaying', 'onprogress', 'onratechange', 'onseeked', 'onseeking', 'onstalled', 'onsuspend', 'ontimeupdate', 'onvolumechange', 'onwaiting', 'onshow', 'ontoggle']; //src: https://www.w3schools.com/tags/ref_eventattributes.asp /** * input: html filename @@ -42,166 +44,190 @@ const parse5 = require('parse5'); * } */ function extractJS(file) { - const JSEvents = ['onafterprint', 'onbeforeprint', 'onbeforeunload', 'onerror', 'onhashchange', 'onload', 'onmessage', 'onoffline', 'ononline', 'onpagehide', 'onpageshow', 'onpopstate', 'onresize', 'onstorage', 'onunload', 'onblur', 'onchange', 'oncontextmenu', 'onfocus', 'oninput', 'oninvalid', 'onreset', 'onsearch', 'onselect', 'onsubmit', 'onkeydown', 'onkeypress', 'onkeyup', 'onclick', 'ondblclick', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onwheel', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onscroll', 'oncopy', 'oncut', 'onpaste', 'onabort', 'oncanplay', 'oncanplaythrough', 'oncuechange', 'ondurationchange', 'onemptied', 'onended', 'onerror', 'onloadeddata', 'onloadedmetadata', 'onloadstart', 'onpause', 'onplay', 'onplaying', 'onprogress', 'onratechange', 'onseeked', 'onseeking', 'onstalled', 'onsuspend', 'ontimeupdate', 'onvolumechange', 'onwaiting', 'onshow', 'ontoggle']; //src: https://www.w3schools.com/tags/ref_eventattributes.asp - - var ret = []; - - htmlTXT = fs.readFileSync(file, 'utf-8'); - const parser = new parse5.SAXParser({ locationInfo: true }); - - var isJS = null; // is set <=> script tag was found - var skip = null; // is set <=> script tag was found - var loc = null; // start tag location - var str = ''; // this is where the scripts text is buffered - - parser.on('startTag', (name, attrs, selfClosing, location) => { // (name: string, attrs: Attribute[], selfClosing: boolean, location?: StartTagLocation) - /* - * Following has to be filtered for: - * - * PARSE anything[onSomeValidEvent='...'] - * - * PARSE script (nincs attr) - * PARSE script[type='text/javascript' || type='application/javascript] - * - * SKIP script[type!='text/javascript' && type!='application/javascript] - * SKIP script[src] - * - */ - if (name === 'script') { - if (attrs.length === 0) { - isJS = true; - skip = false; - } else { - attrs.forEach(attr => { - if (attr.name === 'type' && (attr.value === 'text/javascript' || attr.value === 'application/javascript')) { - isJS = true; - } else { - isJS = false; - } - if (skip || attr.name === 'src') { // if it has a src tag, then skip it - skip = true; - } else { - skip = false; - } - }) - } + + let htmlTXT = fs.readFileSync(file, 'utf-8'); + + /** + * This method extracts line and column information from a given index. + * @param startIndex + * @param endIndex + * @returns {{endOffset: number, startOffset: number}} + */ + function extractLocation(startIndex, endIndex) { + return { + "endOffset": endIndex, + "startOffset": startIndex, } - // PARSE anything[onSomeValidEvent='...'] - attrs.forEach(attr => { - if (JSEvents.includes(attr.name)) { - // fix location to point at the script, not at the tag - var event = attr.name; - var regExp = new RegExp("\\s(" + event + "\\s*=\\s*)(['\"])"); - var str = htmlTXT.substr(location.startOffset, location.endOffset - location.startOffset + 1); //text of the html tag - var match = regExp.exec(str); - var apos = match[2]; - - regExp = new RegExp("\\s(" + event + "\\s*=\\s*" + apos + ")(.*?)(" + apos + ")"); - match = regExp.exec(str); - - var rawtext = match[2]; - var textlength = rawtext.length; - var startOffset = location.startOffset + match.index + match[1].length; - var endOffset = startOffset + textlength; - - ret.push({ - file: file, - type: 'embedded', - node: { name: name, attrs: attrs, selfClosing: selfClosing, location: location }, - event: attr.name, - text: attr.value, - location: { - startOffset: startOffset, - endOffset: endOffset + } + + + let ret = []; + + let isJS = null; // is set <=> script tag was found + let skip = null; // is set <=> script tag was found + let loc = null; // start tag location + let str = ''; // this is where the scripts text is buffered + + + const parser = new htmlparser2.Parser({ + + onopentag(name, attrs) { + /* + * Following has to be filtered for: + * + * PARSE anything[onSomeValidEvent='...'] + * + * PARSE script (nincs attr) + * PARSE script[type='text/javascript' || type='application/javascript] + * + * SKIP script[type!='text/javascript' && type!='application/javascript] + * SKIP script[src] + * + */ + if (name === 'script') { + if (Object.keys(attrs).length === 0) { + isJS = true; + skip = false; + } else { + for (const [attributeName, attributeValue] of Object.entries(attrs)) { + if (attributeName === 'type' && (attributeValue === 'text/javascript' || attributeValue === 'application/javascript')) { + isJS = true; + } + skip = skip || attributeName === 'src'; } - }); - var rep = ""; var len = match[0].length; - for (var i = 0; i < len; i++) rep += " "; //construct an empty string with length of the scriplet found - htmlTXT = htmlTXT.replaceAt(match.index, rep); //clear the script, so it wont be parsed twice + } } - }) - }); - parser.on("text", (text, location) => { - if (isJS && (skip === false)) { - str += text; - loc = location; //location-fix - } - }); + // PARSE anything[onSomeValidEvent='...'] + for (const [attributeName, attributeValue] of Object.entries(attrs)) { + if (JSEvents.includes(attributeName)) { + // fix location to point at the script, not at the tag + // (aki ezeknek a pozíciónak a meghatározására tud jobbat, az nyugodtan javítsa) + let event = attributeName; + let regExp = new RegExp("\\s(" + event + "\\s*=\\s*)(['\"])"); + // let str = htmlTXT.substr(location.startOffset, location.endOffset - location.startOffset + 1); //text of the html tag + let str = htmlTXT.substr(parser.startIndex, parser.endIndex - parser.startIndex + 1); //text of the html tag + //kitaláljuk '-t vagy "-t használ e az attribútum + let match = regExp.exec(str); + let apos = match[2]; + + regExp = new RegExp("\\s(" + event + "\\s*=\\s*" + apos + ")(.*?)(" + apos + ")"); + match = regExp.exec(str); - parser.on("endTag", (name, location) => { - if (name === 'script') { + let rawtext = match[2]; + let textlength = rawtext.length; + let startOffset = parser.startIndex + match.index + match[1].length; + let endOffset = startOffset + textlength; + + ret.push({ + file: file, + type: 'embedded', + node: { + name: name, + attrs: attrs, + selfClosing: false, + location: extractLocation(startOffset, endOffset) + // location: extractLocation(parser.startIndex, parser.endIndex) + }, + event: attributeName, + text: attributeValue, + location: extractLocation(startOffset, endOffset) + }); + let rep = ""; + let len = match[0].length; + for (let i = 0; i < len; i++) { + rep += " "; + } //construct an empty string with length of the scriplet found + htmlTXT = htmlTXT.replaceAt(match.index, rep); //clear the script, so it wont be parsed twice + } + } + }, + + ontext(text) { if (isJS && (skip === false)) { - ret.push({ - file: file, - type: 'script', - text: str, - location: loc - }); + str += text; + // dirty hack to get the real positions for text as parser indexes always shows the actual token's index + const loc2 = extractLocation(parser.startIndex, parser.endIndex); + if (!loc) { + loc = loc2; + } + loc.endOffset = loc2.endOffset; } - //reset for next tag: - str = ''; - isJS = null; - skip = null; - loc = null; - } + }, + + onclosetag(name) { + if (name === 'script') { + if (isJS && (skip === false)) { + // dirty hack to get the real ending index of a script + loc.endOffset = parser.startIndex; + ret.push({ + file: file, + type: 'script', + text: str, + location: loc + }); + } + //reset for next tag: + str = ''; + isJS = null; + skip = null; + loc = null; + } + }, }); parser.write(htmlTXT); - return ret; } /** - * Reads html file, and strips everything from it thats not part of some javascript. The original formatting of the file is not modified (tabs, linebreaks remain), but every other character that's not part of a js is replaced by space. - * @param file Has to be a valid html file - * @returns String the parsed file string - */ -module.exports.extractJSToString = function (file) { - var ret = ""; + * Reads html file, and strips everything from it thats not part of some javascript. The original formatting of the file is not modified (tabs, linebreaks remain), but every other character that's not part of a js is replaced by space. + * @param file Has to be a valid html file + * @returns String the parsed file string + */ +let extractJSToString = function (file) { - var htmlTXT = fs.readFileSync(file, 'utf-8'); + let htmlTXT = fs.readFileSync(file, 'utf-8'); - var scripts = extractJS(file); + let scripts = extractJS(file); if (scripts.length === 0) return ""; - var sortBy = require('lodash.sortby'); scripts = sortBy(scripts, (script) => { return script.location.startOffset; }); - //parse html character entities in attributes, replace them, add padding to preserve lengthof the attribute. + //parse html character entities in attributes, replace them, add padding to preserve length of the attribute. //WARNING this will mess up positions, but only inside the current attribute value, it wont affect global positions. I cant think of a better way to fix this. scripts.forEach(script => { if (script.type === "embedded") { - var rep = script.text; //this is the unescaped script text - var length = script.location.endOffset - script.location.startOffset; - for (; rep.length < length; rep += " "); + let rep = script.text; //this is the unescaped script text + const length = script.location.endOffset - script.location.startOffset; + for (; rep.length < length; rep += " ") ; htmlTXT = htmlTXT.replaceAt(script.location.startOffset, rep); } }); - var toclear = []; + let toclear = []; toclear.push({ start: 0, end: scripts[0].location.startOffset }); - for (var i = 0; i < scripts.length - 1; i++) { + for (let i = 0; i < scripts.length - 1; i++) { toclear.push({ start: scripts[i].location.endOffset, end: scripts[i + 1].location.startOffset }); - }; + } toclear.push({ start: scripts[scripts.length - 1].location.endOffset, end: htmlTXT.length }); toclear.forEach(clear => { - var rep = ""; - for (var i = clear.start; i < clear.end; i++) { - var c = htmlTXT[i]; + let rep = ""; + for (let i = clear.start; i < clear.end; i++) { + const c = htmlTXT[i]; if ((c === '\t') || (c === '\n')) { rep += c; } else { @@ -216,7 +242,6 @@ module.exports.extractJSToString = function (file) { } - // UTILS /** @@ -228,4 +253,6 @@ module.exports.extractJSToString = function (file) { */ String.prototype.replaceAt = function (index, replacement) { return this.substr(0, index) + replacement + this.substr(index + replacement.length); -} \ No newline at end of file +} + +export {extractJSToString} diff --git a/javascript/cl/JSAN/src/assets/options.js b/javascript/cl/JSAN/src/assets/options.js index c1acd27..5fb63b0 100644 --- a/javascript/cl/JSAN/src/assets/options.js +++ b/javascript/cl/JSAN/src/assets/options.js @@ -18,38 +18,87 @@ * limitations under the Licence. */ -const fs = require('fs'); -const path = require('path'); -const getUsage = require('command-line-usage'); //for printing the usage -const commandLineArgs = require('command-line-args'); //for parsing command line args -const toolDescription = require('./toolDescription'); //Tool description +import * as fs from 'fs'; +import * as path from 'path'; +import {default as getUsage} from 'command-line-usage'; +import {default as commandLineArgs} from 'command-line-args'; +import * as toolDescription from './toolDescription.js'; +import * as globals from '../globals.js'; +import {isNull} from "../util/util.js"; //List of command line options const definitions = [ - { name: 'input', alias: 'i', type: String, multiple: true, defaultOption: true, description: 'Input file(s) or directory to be analyzed. Note: simply giving the input file(s) or directory after the last command line parameter will have the same effect too.' }, - { name: 'out', alias: 'o', type: String, defaultValue: 'out', description: 'The output filename for the results to be saved in. It will contain the results in binary format.' }, - { name: 'dumpjsml', alias: 'd', type: Boolean, defaultValue: false, description: 'Dump the output into an XML-style file.' }, - { name: 'externalHardFilter', alias: 'e', type: String, description: 'Filter file specified with relative or absolute path, to filter out certain files from the analysis based on their path names. Filtered files will not appear in the results. The filter file is a simple text file containing lines starting with '+' or '-' characters followed by a regular expression. During the analysis, each input file will be checked for these expressions. If the first character of the last matching expression is '-', then the given file will be excluded from the analysis. If the first character of the last matching expression is '+', or there is no matching expression, then the file will be analyzed. A line starting with a different character than "-" or "+" will be ignored.' }, - { name: 'help', type: Boolean, defaultValue: false, description: 'Prints out the help of JSAN.' }, - { name: 'useRelativePath', alias: 'r', type: Boolean, defaultValue: false, description: 'Relative paths are used in the output if this option is given.' }, - { name: 'html', alias: 'h', type: Boolean, description: 'Analyze not only JavaScript files but extracts JavaScript code snippets from HTML files too if this option is given.' }, - { name: 'stat', type: String, defaultValue: false, description: 'Write memory and runtime stats to the given file.'} + { + name: 'input', + alias: 'i', + type: String, + multiple: true, + defaultOption: true, + description: 'Input file(s) or directory to be analyzed. Note: simply giving the input file(s) or directory after the last command line parameter will have the same effect too.' + }, + { + name: 'out', + alias: 'o', + type: String, + defaultValue: 'out', + description: 'The output filename for the results to be saved in. It will contain the results in binary format.' + }, + { + name: 'dumpjsml', + alias: 'd', + type: Boolean, + defaultValue: false, + description: 'Dump the output into an XML-style file.' + }, + { + name: 'externalHardFilter', + alias: 'e', + type: String, + description: 'Filter file specified with relative or absolute path, to filter out certain files from the analysis based on their path names. Filtered files will not appear in the results. The filter file is a simple text file containing lines starting with " + " or " - " characters followed by a regular expression. During the analysis, each input file will be checked for these expressions. If the first character of the last matching expression is " - ", then the given file will be excluded from the analysis. If the first character of the last matching expression is " + ", or there is no matching expression, then the file will be analyzed. A line starting with a different character than "-" or "+" will be ignored.' + }, + { + name: 'help', + type: Boolean, + defaultValue: false, + description: 'Prints out the help of JSAN.' + }, + { + name: 'useRelativePath', + alias: 'r', + type: Boolean, + defaultValue: false, + description: 'Relative paths are used in the output if this option is given.' + }, + { + name: 'html', + alias: 'h', + type: Boolean, + description: 'Analyze not only JavaScript files but extracts JavaScript code snippets from HTML files too if this option is given.' + }, + { + name: 'stat', + type: String, + defaultValue: false, + description: 'Write memory and runtime stats to the given file.' + }, + //{ name: 'saveEspreeAst', alias: 's', type: Boolean, description: 'Save the AST constructed by Espree into a JSON-style file.' }, + ]; //sections of usage const sections = [ - { - content: toolDescription.banner, - raw: true - }, - { - header: toolDescription.header, - content: toolDescription.description - }, - { - header: 'Options', - optionList: definitions - } + { + content: toolDescription.banner, + raw: true + }, + { + header: toolDescription.header, + content: toolDescription.description + }, + { + header: 'Options', + optionList: definitions + } ]; const usage = getUsage(sections); //construction of usage text @@ -58,33 +107,26 @@ function printUsage() { console.log(usage); } -//Exports -module.exports.printUsage = printUsage; -module.exports.parse = function(){ - var options; - try{ +let parse = function () { + let options; + try { options = commandLineArgs(definitions); options = checkOptions(options); - } - catch(e){ + } catch (e) { console.error("Bad command line!"); console.log(e); printUsage(); } return options; - -}; +}; -function isNull(parameter) { - return typeof parameter === "undefined" || parameter === null; -} //checks whether the parsed command line options are correct function checkOptions(parsedOptions) { - var i; // used in the for loops + let i; // used in the for loops //help if (parsedOptions.help) { @@ -132,14 +174,13 @@ function checkOptions(parsedOptions) { //recursive function which fill the input list function constructInputList(inputFile, parsedOptions) { - if (fs.lstatSync(inputFile).isDirectory()) { - var dirContent = fs.readdirSync(inputFile); - for (var i = 0; i < dirContent.length; i++) { + const dirContent = fs.readdirSync(inputFile); + for (let i = 0; i < dirContent.length; i++) { constructInputList(path.join(inputFile, dirContent[i]), parsedOptions); } } else { - if (path.extname(inputFile) !== ".js" && path.extname(inputFile) !== ".html" || externalHardFiltering(inputFile, parsedOptions.hardFilterArray)) { + if (!globals.supportedExts.includes(path.extname(inputFile)) || externalHardFiltering(inputFile, parsedOptions.hardFilterArray)) { return; } @@ -156,8 +197,8 @@ function externalHardFiltering(inputFile, hardFilterArray) { return; } - var filterIt = false; - for (var i = 0; i < hardFilterArray.length; i++) { + let filterIt = false; + for (let i = 0; i < hardFilterArray.length; i++) { if (inputFile.match(hardFilterArray[i].regex)) { filterIt = hardFilterArray[i].filter; } @@ -169,8 +210,8 @@ function externalHardFiltering(inputFile, hardFilterArray) { } function getHardFilterFiles(hardFilterFile) { - var hardFilterArray = []; - if(!fs.existsSync(hardFilterFile)){ + let hardFilterArray = []; + if (!fs.existsSync(hardFilterFile)) { console.warn("Hard filter file: " + hardFilterFile + " does not exist. Filtering step is being skipped."); return hardFilterArray; } @@ -178,23 +219,32 @@ function getHardFilterFiles(hardFilterFile) { if (fs.lstatSync(hardFilterFile).isFile() && path.extname(hardFilterFile) === ".txt") { fs.readFileSync(hardFilterFile).toString().split('\n').forEach(function (line) { //if empty line then continue - if (line.trim().length == 0){ + if (line.trim().length === 0) { return; } let firstChar = line.substring(0, 1); let regex = line.substring(1, line.length); - if (regex.endsWith("\r")){ - regex = regex.substring(0, regex.length-1); + if (regex.endsWith("\r")) { + // regex = regex.substring(0, regex.length - 1); + regex = regex.trim(); } regex = ".*" + regex + ".*"; + // validate the regex + // if the regex is faulty, throw an error here + try { + new RegExp(regex); + } catch (err) { + console.error(`The following regex is not valid and is being skipped from filtering: "${regex}"`); + return; + } + if (firstChar === "-") { - hardFilterArray.push({ regex: regex, filter: true }); + hardFilterArray.push({regex: regex, filter: true}); } else if (firstChar === "+") { - hardFilterArray.push({ regex: regex, filter: false }); + hardFilterArray.push({regex: regex, filter: false}); } else if (firstChar !== "#") { - console.error("External hard filter contains an invalid line: " + line +"\n"); - return; + console.error("External hard filter contains an invalid line: " + line + "\n"); } }); } else { @@ -203,3 +253,6 @@ function getHardFilterFiles(hardFilterFile) { return hardFilterArray; } + + +export {printUsage, parse} diff --git a/javascript/cl/JSAN/src/assets/scopeManager.js b/javascript/cl/JSAN/src/assets/scopeManager.js new file mode 100644 index 0000000..8cf5003 --- /dev/null +++ b/javascript/cl/JSAN/src/assets/scopeManager.js @@ -0,0 +1,103 @@ +import {analyze} from '@typescript-eslint/scope-manager'; +import {Tree} from '../util/tree' + +class JSANScopeManager { + + constructor(parsingOptions = null) { + this.scopeManager = null; + this.scopeTree = null; + this.currentScope = null; + this.actNode = null; + this.parsingOptions = parsingOptions; + } + + + static extractIdentifiersFromParams(params) { + let identifiers = []; + for (let i = 0; i < params.length; i++) { + //in case of identifier + if (params[i].type === "Identifier" && params[i].name) { + identifiers.push(params[i]); + } + // + else if (params[i].type === "AssignmentPattern") { + //function f(x = 10, y = 20){} + if (params[i].left.type === "Identifier" && params[i].left.name) { + identifiers.push(params[i].left); + } + + //assignment is an array + //function f([x,y] = 10) + //function f([x,y] = [20,30]) + if (params[i].left.type === "ArrayPattern") { + for (let j = 0; j < params[i].left.elements.length; j++) { + if (params[i].left.elements[j].type === "Identifier") { + identifiers.push(params[i].left.elements[j]); + } + } + } + + //TODO: review objectPattern + // https://esprima.readthedocs.io/en/latest/syntax-tree-format.html + if (params[i].left.type === "ObjectPattern") { + for (let j = 0; j < params[i].left.properties.length; j++) { + if (params[i].left.properties[j].key.type === "Identifier") { + identifiers.push(params[i].left.properties[j].key) + } + } + } + } + } + return identifiers; + } + + + enter(ast, node) { + if (!this.scopeManager) { + this.scopeManager = analyze(ast, this.parsingOptions); + } + if ("Program" === node.type) { + this.currentScope = this.scopeManager.acquire(ast); //global scope for that file + this.scopeTree = new Tree({position: undefined, scope: this.currentScope, variables: []}); + this.actNode = this.scopeTree._root; + } else if (/Function/.test(node.type) || /ClassDeclaration/.test(node.type)) { + + //add var to actNode + if (node.id && node.id.name) { + this.actNode.data.variables.push({name: node.id.name, node: node}); + } + + //new scope + this.currentScope = this.scopeManager.acquire(node); // get current function scope + this.actNode = this.scopeTree.add({ + position: node.range, + scope: this.currentScope, + variables: [] + }, this.actNode); + + //add function params to vars + if (/Function/.test(node.type)) { + let idsInAsParams = JSANScopeManager.extractIdentifiersFromParams(node.params); + for (let i = 0; i < idsInAsParams.length; i++) { + this.actNode.data.variables.push({name: idsInAsParams[i].name, node: idsInAsParams[i]}); + } + + } + } else if (/VariableDeclarator/.test(node.type)) { + this.actNode.data.variables.push({name: node.id.name, node: node}); + } + } + + leave(node) { + if (/Function/.test(node.type) || /ClassDeclaration/.test(node.type)) { + if (this.currentScope !== null) { + this.currentScope = this.currentScope.upper; // set to parent scope + } + this.actNode = this.actNode.parent; + } + } +} + +export { + JSANScopeManager +} \ No newline at end of file diff --git a/javascript/cl/JSAN/src/assets/toolDescription.js b/javascript/cl/JSAN/src/assets/toolDescription.js index 6222270..8bd2fca 100644 --- a/javascript/cl/JSAN/src/assets/toolDescription.js +++ b/javascript/cl/JSAN/src/assets/toolDescription.js @@ -18,12 +18,15 @@ * limitations under the Licence. */ -module.exports.banner = - " _ ___ ___ _ _ \n" + - " | |/ __>| . || \\ | \n" + - "_| |\\__ \\| || |\n" + - "\\__/<___/|_|_||_\\_|\n"; +const banner = + " _ ___ ___ _ _ \n" + + " | |/ __>| . || \\ | \n" + + "_| |\\__ \\| || |\n" + + "\\__/<___/|_|_||_\\_|\n"; -module.exports.header = 'JSAN - JavaScript Static Code Analyzer'; -module.exports.description = 'A JavaScript Static Analyzer that uses espree in its core to create an AST. Comment attaching, cross references are handled inside. It also transforms the ast into a Columbus-style AST.' +const header = 'JSAN - JavaScript Static Code Analyzer'; +const description = 'A JavaScript Static Analyzer that uses espree in its core to create an AST. Comment attaching, cross references are handled inside. It also transforms the ast into a Columbus-style AST.' + + +export {banner, header, description} diff --git a/javascript/cl/JSAN/src/assets/varUsages.js b/javascript/cl/JSAN/src/assets/varUsages.js new file mode 100644 index 0000000..bb2c8ef --- /dev/null +++ b/javascript/cl/JSAN/src/assets/varUsages.js @@ -0,0 +1,76 @@ +import * as globals from '../globals.js'; + + +const skip = [ + "VariableDeclarator", + "Function" +]; + +const resolveVariableUsages = function (node, parent, scopeMgr) { + if (/Identifier/.test(node.type)) { + //reference -> create a cross edge + if (skip.indexOf(parent.type) === -1) { + let referencedNode = getReferencedNode(node, scopeMgr.scopeTree); + if (referencedNode !== null) { + if (referencedNode.range[0] === node.range[0] && referencedNode.range[1] === node.range[1]) { + return null; + } + + return { + source: { + label: node.name, + file: globals.getActualFile(), + start: {row: node.loc.start.line, column: node.loc.start.column}, + end: {row: node.loc.end.line, column: node.loc.end.column}, + range: {start: node.range[0], end: node.range[1]}, + node: node + }, + target: { + label: null, + file: globals.getActualFile(), + start: {row: referencedNode.loc.start.line, column: referencedNode.loc.start.column}, + end: {row: referencedNode.loc.end.line, column: referencedNode.loc.end.column}, + range: {start: referencedNode.range[0], end: referencedNode.range[1]}, + node: referencedNode + } + }; + } + } + } + return null; +}; + +function getReferencedNode(identifier, tree) { + let actNode = tree._root; + for (let i = 0; i < actNode.children.length; i++) { + //matching scope + if (actNode.children[i].data.position[0] <= identifier.range[0] && actNode.children[i].data.position[1] >= identifier.range[1]) { + i = 0; + actNode = actNode.children[i]; + } + } + + while (actNode !== null) { + for (let i = 0; i < actNode.data.variables.length; i++) { + if (actNode.data.variables[i].name === identifier.name) { + return actNode.data.variables[i].node; + } + } + + actNode = actNode.parent; + } + return null; +} + +// function setRefersTo(identifier, referencedNode) { +// if (identifier === referencedNode) { +// return; +// } +// if (/VariableDeclarator/.test(referencedNode.type) || /Function/.test(referencedNode.type) || /Identifier/.test(referencedNode.type)) { +// globals.getWrapperOfNode(identifier).setRefersTo(globals.getWrapperOfNode(referencedNode)); +// } +// } + +export { + resolveVariableUsages +} \ No newline at end of file diff --git a/javascript/cl/JSAN/src/ast/astTransformer.js b/javascript/cl/JSAN/src/ast/astTransformer.js index 702c15c..0243089 100644 --- a/javascript/cl/JSAN/src/ast/astTransformer.js +++ b/javascript/cl/JSAN/src/ast/astTransformer.js @@ -18,268 +18,410 @@ * limitations under the Licence. */ -const hashmap = require('hashmap'); -const addon = require('../../javascriptAddon'); -const fs = require('fs'); -const estraverse = require('estraverse'); -const sha1 = require('sha1'); -const path = require('path'); -const Cache = require('lru-cache-node'); - -let crossRefSolver = require('../assets/crossRefSolver'); -let globals = require('../globals'); +import {walk} from 'estree-walker'; +import * as path from 'path'; +import * as globals from '../globals.js'; +import * as varUsages from '../assets/varUsages.js' +import * as scopeManager from '../assets/scopeManager.js' +import * as conversions from './conversions.js'; + +import {default as sha1} from 'sha1'; + +import {default as Cache} from 'lru-cache-node'; + +import {default as program} from "./base/program.js"; + +import {default as classDeclaration} from "./declaration/classDeclaration.js"; +import {default as exportAllDeclaration} from "./declaration/exportAllDeclaration.js"; +import {default as exportDefaultDeclaration} from "./declaration/exportDefaultDeclaration.js"; +import {default as exportNamedDeclaration} from "./declaration/exportNamedDeclaration.js"; +import {default as functionDeclaration} from "./declaration/functionDeclaration.js"; +import {default as importDeclaration} from "./declaration/importDeclaration.js"; +import {default as variableDeclaration} from "./declaration/variableDeclaration.js"; +import {default as variableDeclarator} from "./declaration/variableDeclarator.js"; + +import {default as arrayExpression} from "./expression/arrayExpression.js"; +import {default as arrowFunctionExpression} from "./expression/arrowFunctionExpression.js"; +import {default as assignmentExpression} from "./expression/assignmentExpression.js"; +import {default as awaitExpression} from "./expression/awaitExpression.js"; +import {default as binaryExpression} from "./expression/binaryExpression.js"; +import {default as callExpression} from "./expression/callExpression.js"; +import {default as chainExpression} from "./expression/chainExpression.js"; +import {default as classExpression} from "./expression/classExpression.js"; +import {default as conditionalExpression} from "./expression/conditionalExpression.js"; +import {default as functionExpression} from "./expression/functionExpression.js"; +import {default as identifier} from "./expression/identifier.js"; +import {default as importExpression} from "./expression/importExpression.js"; +import {default as literal} from "./expression/literal.js"; +import {default as logicalExpression} from "./expression/logicalExpression.js"; +import {default as memberExpression} from "./expression/memberExpression.js"; +import {default as metaProperty} from "./expression/metaProperty.js"; +import {default as newExpression} from "./expression/newExpression.js"; +import {default as objectExpression} from "./expression/objectExpression.js"; +import {default as property} from "./expression/property.js"; +import {default as privateIdentifier} from "./expression/privateIdentifier.js"; +import {default as regExpLiteral} from "./expression/regExpLiteral.js"; +import {default as sequenceExpression} from "./expression/sequenceExpression.js"; +import {default as spreadElement} from "./expression/spreadElement.js"; +import {default as superExp} from "./expression/super.js"; +import {default as taggedTemplateExpression} from "./expression/taggedTemplateExpression.js"; +import {default as templateElement} from "./expression/templateElement.js"; +import {default as templateLiteral} from "./expression/templateLiteral.js"; +import {default as thisExpression} from "./expression/thisExpression.js"; +import {default as unaryExpression} from "./expression/unaryExpression.js"; +import {default as updateExpression} from "./expression/updateExpression.js"; +import {default as yieldExpression} from "./expression/yieldExpression.js"; + +import {default as arrayPattern} from "./statement/arrayPattern.js"; +import {default as assignmentPattern} from "./statement/assignmentPattern.js"; +import {default as blockStatement} from "./statement/blockStatement.js"; +import {default as breakStatement} from "./statement/breakStatement.js"; +import {default as catchClause} from "./statement/catchClause.js"; +import {default as continueStatement} from "./statement/continueStatement.js"; +import {default as debuggerStatement} from "./statement/debuggerStatement.js"; +import {default as doWhileStatement} from "./statement/doWhileStatement.js"; +import {default as emptyStatement} from "./statement/emptyStatement.js"; +import {default as expressionStatement} from "./statement/expressionStatement.js"; +import {default as forInStatement} from "./statement/forInStatement.js"; +import {default as forOfStatement} from "./statement/forOfStatement.js"; +import {default as forStatement} from "./statement/forStatement.js"; +import {default as ifStatement} from "./statement/ifStatement.js"; +import {default as labeledStatement} from "./statement/labeledStatement.js"; +import {default as objectPattern} from "./statement/objectPattern.js"; +import {default as restElement} from "./statement/restElement.js"; +import {default as returnStatement} from "./statement/returnStatement.js"; +import {default as switchCase} from "./statement/switchCase.js"; +import {default as switchStatement} from "./statement/switchStatement.js"; +import {default as throwStatement} from "./statement/throwStatement.js"; +import {default as tryStatement} from "./statement/tryStatement.js"; +import {default as whileStatement} from "./statement/whileStatement.js"; +import {default as withStatement} from "./statement/withStatement.js"; + +import {default as classStructure} from "./structure/class.js"; +import {default as classBody} from "./structure/classBody.js"; +import {default as exportSpecifier} from "./structure/exportSpecifier.js"; +import {default as importDefaultSpecifier} from "./structure/importDefaultSpecifier.js"; +import {default as importNamespaceSpecifier} from "./structure/importNamespaceSpecifier.js"; +import {default as importSpecifier} from "./structure/importSpecifier.js"; +import {default as methodDefinition} from "./structure/methodDefinition.js"; +import {default as propertyDefinition} from "./structure/propertyDefinition.js"; + let factory = globals.getFactory(); + let convertNodeToFunction = function (node) { switch (node.type) { case "Program": - return require('./base/program'); //NodeProgramFunction; + return program //NodeProgramFunction; case "EmptyStatement": - return require('./statement/emptyStatement'); + return emptyStatement; case "BlockStatement": - return require('./statement/blockStatement'); + return blockStatement; case "ExpressionStatement": - return require('./statement/expressionStatement'); + return expressionStatement; case "IfStatement": - return require('./statement/ifStatement'); + return ifStatement; case "LabeledStatement": - return require('./statement/labeledStatement'); + return labeledStatement; case "BreakStatement": - return require('./statement/breakStatement'); + return breakStatement; case "ContinueStatement": - return require('./statement/continueStatement'); + return continueStatement; case "WithStatement": - return require('./statement/withStatement'); + return withStatement; case "ReturnStatement": - return require('./statement/returnStatement'); + return returnStatement; case "SwitchStatement": - return require('./statement/switchStatement'); + return switchStatement; case "ThrowStatement": - return require('./statement/throwStatement'); + return throwStatement; case "TryStatement": - return require('./statement/tryStatement'); + return tryStatement; case "WhileStatement": - return require('./statement/whileStatement'); + return whileStatement; case "DoWhileStatement": - return require('./statement/doWhileStatement'); + return doWhileStatement; case "ForStatement": - return require('./statement/forStatement'); + return forStatement; case "ForInStatement": - return require('./statement/forInStatement'); + return forInStatement; case "DebuggerStatement": - return require('./statement/debuggerStatement'); + return debuggerStatement; case "FunctionDeclaration": - return require('./declaration/functionDeclaration'); + return functionDeclaration; case "VariableDeclaration": - return require('./declaration/variableDeclaration'); + return variableDeclaration; case "VariableDeclarator": - return require('./declaration/variableDeclarator'); + return variableDeclarator; + case "ChainExpression": + return chainExpression; + case "ImportExpression": + return importExpression; case "ThisExpression": - return require('./expression/thisExpression'); + return thisExpression; case "ArrayExpression": - return require('./expression/arrayExpression'); + return arrayExpression; case "ObjectExpression": - return require('./expression/objectExpression'); + return objectExpression; case "Property": - return require('./expression/property'); - case "AssignmentProperty": - return require('./expression/assignmentExpression'); + return property; case "FunctionExpression": - return require('./expression/functionExpression'); + return functionExpression; case "SequenceExpression": - return require('./expression/sequenceExpression'); + return sequenceExpression; case "UnaryExpression": - return require('./expression/unaryExpression'); + return unaryExpression; case "BinaryExpression": - return require('./expression/binaryExpression'); + return binaryExpression; case "AssignmentExpression": - return require('./expression/assignmentExpression'); + return assignmentExpression; case "UpdateExpression": - return require('./expression/updateExpression'); + return updateExpression; case "LogicalExpression": - return require('./expression/logicalExpression'); + return logicalExpression; case "ConditionalExpression": - return require('./expression/conditionalExpression'); + return conditionalExpression; case "CallExpression": - return require('./expression/callExpression'); + return callExpression; case "NewExpression": - return require('./expression/newExpression'); + return newExpression; case "MemberExpression": - return require('./expression/memberExpression'); + return memberExpression; case "SwitchCase": - return require('./statement/switchCase'); + return switchCase; case "CatchClause": - return require('./statement/catchClause'); + return catchClause; case "Identifier": - return require('./expression/identifier'); + return identifier; case "Literal": - return require('./expression/literal'); + return literal; case "RegExpLiteral": - return require('./expression/regExpLiteral'); + return regExpLiteral; case "YieldExpression": - return require('./expression/yieldExpression'); + return yieldExpression; case "Super": - return require('./expression/super'); + return superExp; case "SpreadElement": - return require('./expression/spreadElement'); + return spreadElement; case "ArrowFunctionExpression": - return require('./expression/arrowFunctionExpression'); + return arrowFunctionExpression; case "TaggedTemplateExpression": - return require('./expression/taggedTemplateExpression'); + return taggedTemplateExpression; case "ClassExpression": - return require('./expression/classExpression'); + return classExpression; case "TemplateLiteral": - return require('./expression/templateLiteral'); + return templateLiteral; case "TemplateElement": - return require('./expression/templateElement'); + return templateElement; case "MetaProperty": - return require('./expression/metaProperty'); + return metaProperty; case "ForOfStatement": - return require('./statement/forOfStatement'); + return forOfStatement; case "AssignmentPattern": - return require('./statement/assignmentPattern'); + return assignmentPattern; case "ArrayPattern": - return require('./statement/arrayPattern'); + return arrayPattern; case "RestElement": - return require('./statement/restElement'); + return restElement; case "ObjectPattern": - return require('./statement/objectPattern'); - case "Line": - return require('./base/comment'); - case "Block": - return require('./base/comment'); + return objectPattern; case "ImportDeclaration": - return require('./declaration/importDeclaration'); + return importDeclaration; case "ExportNamedDeclaration": - return require('./declaration/exportNamedDeclaration'); + return exportNamedDeclaration; case "ExportDefaultDeclaration": - return require('./declaration/exportDefaultDeclaration'); + return exportDefaultDeclaration; case "ExportAllDeclaration": - return require('./declaration/exportAllDeclaration'); + return exportAllDeclaration; case "ClassDeclaration": - return require('./declaration/classDeclaration'); + return classDeclaration; case "Class": - return require('./structure/class'); + return classStructure; case "ClassBody": - return require('./structure/classBody'); + return classBody; case "MethodDefinition": - return require('./structure/methodDefinition'); + return methodDefinition; case "ImportSpecifier": - return require('./structure/importSpecifier'); + return importSpecifier; case "ExportSpecifier": - return require('./structure/exportSpecifier'); + return exportSpecifier; case "ImportNamespaceSpecifier": - return require('./structure/importNamespaceSpecifier'); + return importNamespaceSpecifier; case "ImportDefaultSpecifier": - return require('./structure/importDefaultSpecifier'); + return importDefaultSpecifier; case "AwaitExpression": - return require('./expression/awaitExpression'); + return awaitExpression; + case "ClassProperty": // TODO: Remove this once parser correctly handles PropertyDefinitions + case "PropertyDefinition": + return propertyDefinition; + case "PrivateIdentifier": + case "TSPrivateIdentifier": // TODO: Remove this once parser correctly handles private identifiers + return privateIdentifier; + case "Line": + case "Block": + /* + Intentionally ignored types + */ + break; default: - console.log("Not recognized type: " + node.type + "\n"); - + console.log("Could not recognize type: " + node.type); } }; /** - * Transforms the leading and trailing comments attached by Espree for a node. - * Leading Block comment at the beginning handled as a comment for the whole program. - * @param {type} node - * @param {type} wrapper + * Gets the absolute or relative path of a file path. + * @param filePath */ -function handleComments(node) { - let wrapper = globals.getWrapperOfNode(node); - - if (node.leadingComments !== undefined && node.leadingComments !== null) { - for (let j = 0; j < node.leadingComments.length; j++) { - if (node.leadingComments[j] !== null && node.leadingComments[j] !== undefined) { - - if (globals.isCommentExists(node.leadingComments[j])) { - node.leadingComments.splice(j, 1); - j--; - continue; - } +function getFilePath(filePath) { + if (globals.getOption('useRelativePath') && path.isAbsolute(filePath)) { + return path.relative(process.cwd(), filePath); + } + return filePath; +} - let leadingComment = factory.createCommentWrapper(); - leadingComment.setText(node.leadingComments[j].value); - globals.setPositionInfo(node.leadingComments[j], leadingComment); - leadingComment.setType("ct" + node.leadingComments[j].type); - leadingComment.setLocation("clLeading"); +function createASGNode(node, parent) { + let func = convertNodeToFunction(node); + if (func !== undefined) { + let nodeWrapper = func(node, parent, true); + if (nodeWrapper !== undefined) { + globals.putNodeWrapperPair(node, nodeWrapper); + } + } +} - globals.addComment(node.leadingComments[j]); +/** + * Transforms the Espree AST + * + * @param {type} astSet: an ast created by espree + * @param {type} parsingOptions: The espree runner configurations + */ +let transform = function (astSet, parsingOptions) { + astSet.forEach(ast => { + globals.setActualFile(ast.filename); + //first traverse - //Handle program comment at the beginning - if (node.leadingComments[j].loc.start.line === 1 && node.leadingComments[j].type === "Block") { - globals.getWrapperOfNode(globals.getActualProgramNode()).addComments(leadingComment); + walk(ast, { + enter: function (node, parent) { + createASGNode(node, parent); + } + }); + }); + astSet.forEach(ast => { + globals.setActualFile(ast.filename); - //attach this comment to the program - globals.getActualProgramNode().leadingComments = []; - globals.getActualProgramNode().leadingComments.push(node.leadingComments[j]); + //second traverse + walk(ast, { + enter: function (node, parent) { + // console.log(node.type); + handleComments(node); + let func = convertNodeToFunction(node); - //remove comment from the original node - node.leadingComments.splice(j, 1); - j--; - } - else { - wrapper.addComments(leadingComment); + if (func !== undefined) { + func(node, parent, false); } - } + }, + // leave: function (node, parent) { + // console.log("Leaving node type " + node.type) + // } + }); + }); + console.log("Transform finished!"); +}; +let handleComments = function (node) { + if (node.comments) { + for (let comment of node.comments) { + const commentWrapper = factory.createCommentWrapper(); + commentWrapper.setText(comment.value); + commentWrapper.setType(conversions.convertCommentType(comment.type)); + commentWrapper.setLocation(conversions.convertCommentLocation(comment)); + globals.setPositionInfo(comment, commentWrapper); + const nodeWrapper = globals.getWrapperOfNode(node); + if (nodeWrapper !== undefined) { + nodeWrapper.addComments(commentWrapper); + } else { + console.log("Cannot add comments to undefined node.") + } } } +} - if (node.trailingComments !== undefined && node.trailingComments !== null) { - for (let j = 0; j < node.trailingComments.length; j++) { - if (node.trailingComments[j] !== null && node.trailingComments[j] !== undefined) { +let saveAST = function (filename, dumpjsml) { + factory.saveAST(filename + ".jssi", dumpjsml); +}; - if (globals.isCommentExists(node.trailingComments[j]) || Math.abs(node.loc.end.line - node.trailingComments[j].loc.start.line) > 1) { - node.trailingComments.splice(j, 1); - j--; - continue; - } - let trailingComment = factory.createCommentWrapper(); - trailingComment.setText(node.trailingComments[j].value); - globals.setPositionInfo(node.trailingComments[j], trailingComment); - trailingComment.setType("ct" + node.trailingComments[j].type); - trailingComment.setLocation("clTrailing"); - wrapper.addComments(trailingComment); +function variableUsages(astSet) { + let vus = []; + astSet.forEach(ast => { + const sm = new scopeManager.JSANScopeManager() - globals.addComment(node.trailingComments[j]); + //TODO: Move this? + walk(ast, { + enter: (node, parent) => { + sm.enter(ast, node); + }, + leave: (node, parent) => { + sm.leave(node); } - } - } + }) + + globals.setActualFile(ast.filename); + walk(ast, { + enter: function (node, parent) { + let varUse = varUsages.resolveVariableUsages(node, parent, sm); + if (varUse !== null) { + vus.push(varUse); + } + } + }); + }); + return vus; } -/** - * Detects all unattached comments in the file - */ -function detectUnAttachedComments(node) { - if (!node || node.type !== 'Program') { - return null; - } - //initially all the comments, then remove attached comments - //var unattachedComments = Object.assign({}, node.comments); - let unattachedComments = node.comments; - for (let i = 0; i < unattachedComments.length; i++) { - if (globals.isCommentExists(unattachedComments[i])) { - unattachedComments.splice(i, 1); - i--; + +let makeHash = function (element) { + return sha1(element.source.file + ":" + element.source.range.start + ":" + element.source.range.end) + sha1(element.target.file + ":" + element.target.range.start + ":" + element.target.range.end); +}; + + +let resolveNode = function (ast, filename, range_start, range_end, inner = false) { + const searchNode = { + file: filename, range: { + start: range_start, end: range_end } - } - return unattachedComments; -} + }; + let result = null; + let status = false; + ast.forEach(astNode => { + if (status || astNode.filename !== searchNode.file) { + return; + } + globals.setActualFile(astNode.filename); + + // find the most inner node which has the same exact source position + walk(astNode, { + enter: function (node) { + if (status) { + if (inner) { // return the most inner node + if (node.range[0] !== searchNode.range.start || node.range[1] !== searchNode.range.end) { + return; + } + } else { // return the most outer node + return; + } -/** - * Gets the absolute or relative path of a file path. - * @param filePath - */ -function getFilePath(filePath) { - if (globals.getOption('useRelativePath') && path.isAbsolute(filePath)) { - return path.relative(process.cwd(), filePath); - } - return filePath; -} + } + if (node.range[0] === searchNode.range.start && node.range[1] === searchNode.range.end && node.type !== 'Program') { + status = true; + result = node; + } + } + }); + }); + return result; +}; /** * Bind the references for JSAN2LIM. This method callable more. @@ -288,8 +430,9 @@ function getFilePath(filePath) { * @param name The name of bindings data * @param astSet The ColumbusStyle AST * @param references A JSON, which contains the links. + * @param type */ -module.exports.binder = function (name, astSet, references, type) { +const binder = function (name, astSet, references, type) { let success = 0; let numberOfReferences = references.length; let cache = new Cache(1000); @@ -297,7 +440,7 @@ module.exports.binder = function (name, astSet, references, type) { references.forEach(element => { let hash = makeHash(element); - if(global.binded.indexOf(hash)!==-1){ + if (global.binded.indexOf(hash) !== -1) { numberOfReferences--; return; } @@ -305,24 +448,25 @@ module.exports.binder = function (name, astSet, references, type) { let sourceFile = getFilePath(element.source.file); - let hashSource = sha1(element.source.file+":"+element.source.range.start+":"+element.source.range.end); + let hashSource = sha1(element.source.file + ":" + element.source.range.start + ":" + element.source.range.end); if (!cache.contains(hashSource)) { - let wrappedNode = globals.getWrapperOfNode(crossRefSolver.resolveNode(astSet, sourceFile, element.source.range.start, element.source.range.end, true)); + let wrappedNode = globals.getWrapperOfNode(resolveNode(astSet, sourceFile, element.source.range.start, element.source.range.end, true)); cache.set(hashSource, wrappedNode || null); } let sourcenode = cache.get(hashSource); if (sourcenode === null) { return; } + // Only for cross-ref binding if (element.target.file === "Native") { numberOfReferences--; return; } globals.setActualFile(element.target.file); let targetFile = getFilePath(element.target.file); - let hashTarget = sha1(element.target.file+":"+element.target.range.start+":"+element.target.range.end); + let hashTarget = sha1(element.target.file + ":" + element.target.range.start + ":" + element.target.range.end); if (!cache.contains(hashTarget)) { - let wrappedNode = globals.getWrapperOfNode(crossRefSolver.resolveNode(astSet, targetFile, element.target.range.start, element.target.range.end, false)); + let wrappedNode = globals.getWrapperOfNode(resolveNode(astSet, targetFile, element.target.range.start, element.target.range.end, false)); cache.set(hashTarget, wrappedNode || null); } let targetnode = cache.get(hashTarget); @@ -330,7 +474,7 @@ module.exports.binder = function (name, astSet, references, type) { return; } try { - if (type === "addCalls"){ + if (type === "addCalls") { sourcenode.addCalls(targetnode); } else if (type === "setRefersTo") { sourcenode.setRefersTo(targetnode); @@ -347,113 +491,11 @@ module.exports.binder = function (name, astSet, references, type) { console.log("Binding " + name + ": " + success + "/" + numberOfReferences); }; -let makeHash = function(element){ - return sha1(element.source.file+":"+element.source.range.start+":"+element.source.range.end)+sha1(element.target.file+":"+element.target.range.start+":"+element.target.range.end); -}; - -module.exports.variableUsages = function (astSet) { - let vus = []; - astSet.forEach(ast => { - globals.setActualFile(ast.filename); - estraverse.traverse(ast, { - enter: function (node, parent) { - let varUse = crossRefSolver.resolveVariableUsages(node, parent); - if (varUse !== null) { - vus.push(varUse); - } - } - }); - }); - return vus; -}; - -module.exports.variableUsages = function (astSet) { - let vus = []; - astSet.forEach(ast => { - globals.setActualFile(ast.filename); - estraverse.traverse(ast, { - enter: function (node, parent) { - let varUse = crossRefSolver.resolveVariableUsages(node, parent); - if (varUse !== null) { - vus.push(varUse); - } - } - }); - }); - return vus; -}; -/** - * Transforms the Espree AST - * - * @param {type} astSet: an ast created by espree - * @param {type} parsingOptions: The espree runner configurations - */ -module.exports.transform = function (astSet, parsingOptions) { - astSet.forEach(ast => { - globals.setActualFile(ast.filename); - //first traverse - crossRefSolver.setParsingOptions(parsingOptions); - estraverse.traverse(ast, { - enter: function (node, parent) { - let func = convertNodeToFunction(node); - if (func !== undefined) { - let nodeWrapper = func(node, parent, true); - if (nodeWrapper !== undefined) { - globals.putNodeWrapperPair(node, nodeWrapper); - } - } - //gathering the scopes and the identifiers located in them - crossRefSolver.gatherScopes(ast, node, "enter"); - }, - leave: function (node, parent) { - crossRefSolver.gatherScopes(ast, node, "leave"); - } - }); - }); - - astSet.forEach(ast => { - globals.setActualFile(ast.filename); - //second traverse - estraverse.traverse(ast, { - enter: function (node, parent) { - let func = convertNodeToFunction(node); - if (func !== undefined) { - func(node, parent, false); - - } - //handle comments - handleComments(node); - }, - leave: function (node, parent) { - if (node.type === 'Program') { - let comments = detectUnAttachedComments(node); - - //create these unattached comments and attach them to the program - for (let i = 0; i < comments.length; i++) { - let comment = factory.createCommentWrapper(); - comment.setText(comments[i].value); - globals.setPositionInfo(comments[i], comment); - comment.setType("ct" + comments[i].type); - comment.setLocation("clTrailing"); - let programWrapper = globals.getWrapperOfNode(node); - programWrapper.addComments(comment); - - if (node.loc.end.line < comments[i].loc.start.line || (node.loc.end.line === comments[i].loc.start.line && node.loc.end.column < comments[i].loc.start.column)) { - programWrapper.setPosition({ - 'endline': comments[i].loc.end.line, - 'endcol': comments[i].loc.end.column, - 'wideendline': comments[i].loc.end.line, - 'wideendcol': comments[i].loc.end.column - }); - } - } - } - } - }); - }); -}; - -module.exports.saveAST = function (filename, dumpjsml) { - factory.saveAST(filename + ".jssi", dumpjsml); -}; +export { + createASGNode, + transform, + saveAST, + variableUsages, + binder, +} diff --git a/javascript/cl/JSAN/src/ast/base/program.js b/javascript/cl/JSAN/src/ast/base/program.js index 0e19b17..c81925f 100644 --- a/javascript/cl/JSAN/src/ast/base/program.js +++ b/javascript/cl/JSAN/src/ast/base/program.js @@ -18,41 +18,34 @@ * limitations under the Licence. */ -const path = require('path'); -const conversions = require('../conversions'); +import * as path from 'path'; +import * as conversions from '../conversions.js'; +import * as globals from '../../globals.js'; -var globals = require('../../globals'); -var factory = globals.getFactory(); +const factory = globals.getFactory(); - - -module.exports = function (node, parent, firstVisit) { +export default function (node, parent, firstVisit) { globals.setActualProgramNode(node); - var actualJsFilePath = globals.getActualFile(); + const actualJsFilePath = globals.getActualFile(); //new program => clear comments - globals.clearCommentMap(); if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var program = factory.createProgramWrapper(factory); + const program = factory.createProgramWrapper(); program.setName(path.basename(actualJsFilePath, path.extname(actualJsFilePath))); globals.setPositionInfo(node, program); - factory.getRoot(factory).addPrograms(program); + factory.getRoot().addPrograms(program); program.setSourceType(conversions.convertSourceType(node.sourceType)); return program; } else { - var programWrapper = globals.getWrapperOfNode(node); + const programWrapper = globals.getWrapperOfNode(node); if (node.body != null) { - for (var i = 0; i < node.body.length; i++) { + for (let i = 0; i < node.body.length; i++) { if (node.body[i] != null) { - var bodyWrapper = globals.getWrapperOfNode(node.body[i]); - try { - programWrapper.addBody(bodyWrapper); - } catch (e) { - console.error("Cannot add body to program - " + e + "\n"); - } + + globals.safeSet(programWrapper, "addBody", node.body[i], "PROGRAM - Cannot add body to program!"); } } } diff --git a/javascript/cl/JSAN/src/ast/conversions.js b/javascript/cl/JSAN/src/ast/conversions.js index 14a1b60..9a74b20 100644 --- a/javascript/cl/JSAN/src/ast/conversions.js +++ b/javascript/cl/JSAN/src/ast/conversions.js @@ -42,6 +42,16 @@ const sourceTypes = { 'module': 'pstModule' }; +const commentTypes = { + 'Line': 'ctLine', + 'Block': 'ctBlock' +}; + +const commentLocations = { + 'trailing': 'clTrailing', + 'leading': 'clLeading' +}; + const unaryOperators = { '-': "unoMinus", '+': "unoPlus", @@ -79,6 +89,7 @@ const additionalOperators = { '--': 'upoDecrement', '&&': 'looAnd', '||': 'looOr', + '??': 'looNullishCoalescing', '=': 'asoAssign', '+=': 'asoAdd', '-=': 'asoSubtract', @@ -91,33 +102,53 @@ const additionalOperators = { '|=': 'asoBitwiseOr', '^=': 'asoBitwiseXor', '&=': 'asoBitwiseAnd', - '**=': 'asoExponentiation' + '**=': 'asoExponentiation', + // ES2021 + '||=': 'asoOr', + '&&=': 'asoAnd', + '??=': 'asoNullishCoalescing' }; -//-------------------------- -//-----Module Exports------- -//-------------------------- -module.exports.convertPropertyKind = function (kind) { +const convertPropertyKind = function (kind) { return propertyKinds[kind] === undefined ? 'unrecognized' : propertyKinds[kind]; }; -module.exports.convertDeclarationKind = function (kind) { +const convertDeclarationKind = function (kind) { return declarationKinds[kind] === undefined ? 'unrecognized' : declarationKinds[kind]; }; -module.exports.convertMethodDefinitionKind = function (kind) { +const convertMethodDefinitionKind = function (kind) { return methodDefinitionKinds[kind] === undefined ? 'unrecognized' : methodDefinitionKinds[kind]; }; -module.exports.convertSourceType = function (sourcetype) { +const convertSourceType = function (sourcetype) { return sourceTypes[sourcetype] === undefined ? 'unrecognized' : sourceTypes[sourcetype]; }; -module.exports.convertUnaryOperatorToString = function (operator) { +const convertUnaryOperatorToString = function (operator) { return unaryOperators[operator] === undefined ? 'unrecognized' : unaryOperators[operator]; }; -module.exports.convertOperatorToString = function (operator) { +const convertOperatorToString = function (operator) { return additionalOperators[operator] === undefined ? 'unrecognized' : additionalOperators[operator]; }; + +const convertCommentType = function (type) { + return commentTypes[type] === undefined ? 'unrecognized' : commentTypes[type]; +} + +const convertCommentLocation = function convertCommentLocation(comment) { + return comment.leading ? commentLocations.leading : commentLocations.trailing; +}; + +export { + convertPropertyKind, + convertDeclarationKind, + convertMethodDefinitionKind, + convertSourceType, + convertOperatorToString, + convertUnaryOperatorToString, + convertCommentType, + convertCommentLocation +} diff --git a/javascript/cl/JSAN/src/ast/declaration/classDeclaration.js b/javascript/cl/JSAN/src/ast/declaration/classDeclaration.js index c71ecb7..43ed96a 100644 --- a/javascript/cl/JSAN/src/ast/declaration/classDeclaration.js +++ b/javascript/cl/JSAN/src/ast/declaration/classDeclaration.js @@ -18,46 +18,32 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var classDeclaration = factory.createClassDeclarationWrapper(); + const classDeclaration = factory.createClassDeclarationWrapper(); globals.setPositionInfo(node, classDeclaration); return classDeclaration; } else { - var classDeclarationWrapper = globals.getWrapperOfNode(node); + const classDeclarationWrapper = globals.getWrapperOfNode(node); if (node.superClass != null) { - var superClassWrapper = globals.getWrapperOfNode(node.superClass); - try { - classDeclarationWrapper.setSuperClass(superClassWrapper); - } catch (e) { - console.error("CLASSDECLARATION - Could not add superClass! Reason of the error: " + e + "\n"); - } + globals.safeSet(classDeclarationWrapper, "setSuperClass", node.superClass, "CLASSDECLARATION - Could not add superClass!"); } if (node.body != null) { - var bodyWrapper = globals.getWrapperOfNode(node.body); - try { - classDeclarationWrapper.setBody(bodyWrapper); - } catch (e) { - console.error("CLASSDECLARATION - Could not set body! Reason of the error: " + e + "\n"); - } + globals.safeSet(classDeclarationWrapper, "setBody", node.body, "CLASSDECLARATION - Could not set body"); } if (node.id != null) { - var identifierWrapper = globals.getWrapperOfNode(node.id); - try { - classDeclarationWrapper.setIdentifier(identifierWrapper); - } catch (e) { - console.error("CLASSDECLARATION - Could not set Identifier! Reason of the error: " + e + "\n"); - } + globals.safeSet(classDeclarationWrapper, "setIdentifier", node.id, "CLASSDECLARATION - Could not set Identifier"); } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/declaration/exportAllDeclaration.js b/javascript/cl/JSAN/src/ast/declaration/exportAllDeclaration.js index fc0ef9e..7625fb7 100644 --- a/javascript/cl/JSAN/src/ast/declaration/exportAllDeclaration.js +++ b/javascript/cl/JSAN/src/ast/declaration/exportAllDeclaration.js @@ -18,28 +18,27 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; +import {createASGNode} from '../astTransformer'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var exportAllDeclaration = factory.createExportAllDeclarationWrapper(); + const exportAllDeclaration = factory.createExportAllDeclarationWrapper(); globals.setPositionInfo(node, exportAllDeclaration); return exportAllDeclaration; } else { - var exportAllDeclarationWrapper = globals.getWrapperOfNode(node); - - if (node.source != null) { - var sourceWrapper = globals.getWrapperOfNode(node.source); - try { - exportAllDeclarationWrapper.setSource(sourceWrapper); - } catch (e) { - console.error("EXPORTALLDECLARATION - Could not set source! Reason of the error: " + e + "\n"); - } + const exportAllDeclarationWrapper = globals.getWrapperOfNode(node); + if (node.source !== null) { + globals.safeSet(exportAllDeclarationWrapper, "setSource", node.source, "EXPORTALLDECLARATION - Could not set source node!"); } + if (node.exported !== null) { + globals.safeSet(exportAllDeclarationWrapper, "setExported", node.exported, "EXPORTALLDECLARATION - Could not set exported node!") + } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/declaration/exportDefaultDeclaration.js b/javascript/cl/JSAN/src/ast/declaration/exportDefaultDeclaration.js index bfd9d47..9bbef9c 100644 --- a/javascript/cl/JSAN/src/ast/declaration/exportDefaultDeclaration.js +++ b/javascript/cl/JSAN/src/ast/declaration/exportDefaultDeclaration.js @@ -18,28 +18,23 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var exportDefaultDeclaration = factory.createExportDefaultDeclarationWrapper(); + const exportDefaultDeclaration = factory.createExportDefaultDeclarationWrapper(); globals.setPositionInfo(node, exportDefaultDeclaration); return exportDefaultDeclaration; } else { - var exportDefaultDeclarationWrapper = globals.getWrapperOfNode(node); + const exportDefaultDeclarationWrapper = globals.getWrapperOfNode(node); if (node.declaration != null) { - var declarationWrapper = globals.getWrapperOfNode(node.declaration); - try { - exportDefaultDeclarationWrapper.setDeclaration(declarationWrapper); - } catch (e) { - console.error("EXPORTDEFAULTDECLARATION - Could not set declaration! Reason of the error: " + e + "\n"); - } + globals.safeSet(exportDefaultDeclarationWrapper, "setDeclaration", node.declaration, "EXPORTDEFAULTDECLARATION - Could not set declaration!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/declaration/exportNamedDeclaration.js b/javascript/cl/JSAN/src/ast/declaration/exportNamedDeclaration.js index 980fd0d..3829267 100644 --- a/javascript/cl/JSAN/src/ast/declaration/exportNamedDeclaration.js +++ b/javascript/cl/JSAN/src/ast/declaration/exportNamedDeclaration.js @@ -18,49 +18,35 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var exportNamedDeclaration = factory.createExportNamedDeclarationWrapper(); + const exportNamedDeclaration = factory.createExportNamedDeclarationWrapper(); globals.setPositionInfo(node, exportNamedDeclaration); return exportNamedDeclaration; } else { - var exportNamedDeclarationWrapper = globals.getWrapperOfNode(node); + const exportNamedDeclarationWrapper = globals.getWrapperOfNode(node); if (node.source != null) { - var sourceWrapper = globals.getWrapperOfNode(node.source); - try { - exportNamedDeclarationWrapper.setSource(sourceWrapper); - } catch (e) { - console.error("EXPORTNAMEDDECLARATION - Could not set source! Reason of the error: " + e + "\n"); - } + globals.safeSet(exportNamedDeclarationWrapper, "setSource", node.source, "EXPORTNAMEDDECLARATION - Could not set source!"); } if (node.declaration != null) { - var declarationWrapper = globals.getWrapperOfNode(node.declaration); - try { - exportNamedDeclarationWrapper.setDeclaration(declarationWrapper); - } catch (e) { - console.error("EXPORTNAMEDDECLARATION - Could not set declaration! Reason of the error: " + e + "\n"); - } + globals.safeSet(exportNamedDeclarationWrapper, "setDeclaration", node.declaration, "EXPORTNAMEDDECLARATION - Could not set declaration!") } if (node.specifiers != null) { - for (var i = 0; i < node.specifiers.length; i++) { + for (let i = 0; i < node.specifiers.length; i++) { if (node.specifiers[i] != null) { - var specifiersWrapper = globals.getWrapperOfNode(node.specifiers[i]); - try { - exportNamedDeclarationWrapper.addSpecifiers(specifiersWrapper); - } catch (e) { - console.error("EXPORTNAMEDDECLARATION - Could nout add specifier! Reason of the error: " + e + "\n"); - } + globals.safeSet(exportNamedDeclarationWrapper, "addSpecifiers", node.specifiers[i], "EXPORTNAMEDDECLARATION - Could not add specifier!") } } } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/declaration/functionDeclaration.js b/javascript/cl/JSAN/src/ast/declaration/functionDeclaration.js index c796bdd..44586db 100644 --- a/javascript/cl/JSAN/src/ast/declaration/functionDeclaration.js +++ b/javascript/cl/JSAN/src/ast/declaration/functionDeclaration.js @@ -18,61 +18,42 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var functionDeclaration = factory.createFunctionDeclarationWrapper(); + const functionDeclaration = factory.createFunctionDeclarationWrapper(); globals.setPositionInfo(node, functionDeclaration); functionDeclaration.setGenerator(node.generator); functionDeclaration.setAsync(node.async); return functionDeclaration; } else { - var functionDeclarationWrapper = globals.getWrapperOfNode(node); + const functionDeclarationWrapper = globals.getWrapperOfNode(node); if (node.params != null) { - for (var i = 0; i < node.params.length; i++) { + for (let i = 0; i < node.params.length; i++) { if (node.params[i] != null) { - var paramsWrapper = globals.getWrapperOfNode(node.params[i]); - try { - functionDeclarationWrapper.addParams(paramsWrapper); - } catch (e) { - console.error("FUNCTIONDECLARATION - Could not add param! Reason of the error: " + e + "\n"); - } + globals.safeSet(functionDeclarationWrapper, "addParams", node.params[i], "FUNCTIONDECLARATION - Could not add param"); } } } if (node.declaration != null) { - var declarationWrapper = globals.getWrapperOfNode(node.declaration); - try { - functionDeclarationWrapper.setDeclaration(declarationWrapper); - } catch (e) { - console.error("FUNCTIONDECLARATION - Could not set declaration! Reason of the error: " + e + "\n"); - } + globals.safeSet(functionDeclarationWrapper, "setDeclaration", node.declaration, "FUNCTIONDECLARATION - Could not set declaration!"); } if (node.body != null) { - var bodyWrapper = globals.getWrapperOfNode(node.body); - try { - functionDeclarationWrapper.setBody(bodyWrapper); - } catch (e) { - console.error("FUNCTIONDECLARATION - Could not set body! Reason of the error: " + e + "\n"); - } + globals.safeSet(functionDeclarationWrapper, "setBody", node.body, "FUNCTIONDECLARATION - Could not set body!"); } if (node.id != null) { - var identifierWrapper = globals.getWrapperOfNode(node.id); - try { - functionDeclarationWrapper.setIdentifier(identifierWrapper); - } catch (e) { - console.error("FUNCTIONDECLARATION - Could not set identifier! Reason of the error: " + e + "\n"); - } + globals.safeSet(functionDeclarationWrapper, "setIdentifier", node.id, "FUNCTIONDECLARATION - Could not set identifier!"); } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/declaration/importDeclaration.js b/javascript/cl/JSAN/src/ast/declaration/importDeclaration.js index abc1b66..94e7c6e 100644 --- a/javascript/cl/JSAN/src/ast/declaration/importDeclaration.js +++ b/javascript/cl/JSAN/src/ast/declaration/importDeclaration.js @@ -18,40 +18,31 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var importDeclaration = factory.createImportDeclarationWrapper(); + const importDeclaration = factory.createImportDeclarationWrapper(); globals.setPositionInfo(node, importDeclaration); return importDeclaration; } else { - var importDeclarationWrapper = globals.getWrapperOfNode(node); + const importDeclarationWrapper = globals.getWrapperOfNode(node); if (node.source != null) { - var sourceWrapper = globals.getWrapperOfNode(node.source); - try { - importDeclarationWrapper.setSource(sourceWrapper); - } catch (e) { - console.error("IMPORTDECLARATION - Could not set source! Reason of the error: " + e + "\n"); - } + globals.safeSet(importDeclarationWrapper, "setSource", node.source, "IMPORTDECLARATION - Could not set source!"); } if (node.specifiers != null) { - for (var i = 0; i < node.specifiers.length; i++) { + for (let i = 0; i < node.specifiers.length; i++) { if (node.specifiers[i] != null) { - var specifiersWrapper = globals.getWrapperOfNode(node.specifiers[i]); - try { - importDeclarationWrapper.addSpecifiers(specifiersWrapper); - } catch (e) { - console.error("IMPORTDECLARATION - Could not add specifiers! Reason of the error: " + e + "\n"); - } + globals.safeSet(importDeclarationWrapper, "addSpecifiers", node.specifiers[i], "IMPORTDECLARATION - Could not add specifiers!"); } } } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/declaration/variableDeclaration.js b/javascript/cl/JSAN/src/ast/declaration/variableDeclaration.js index 42b41a8..eb630da 100644 --- a/javascript/cl/JSAN/src/ast/declaration/variableDeclaration.js +++ b/javascript/cl/JSAN/src/ast/declaration/variableDeclaration.js @@ -18,32 +18,28 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); -const conversions = require('../conversions'); +import * as globals from '../../globals.js'; +import * as conversions from '../conversions.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var variableDeclaration = factory.createVariableDeclarationWrapper(); + const variableDeclaration = factory.createVariableDeclarationWrapper(); globals.setPositionInfo(node, variableDeclaration); variableDeclaration.setKind(conversions.convertDeclarationKind(node.kind)); return variableDeclaration; } else { - var variableDeclarationWrapper = globals.getWrapperOfNode(node); + const variableDeclarationWrapper = globals.getWrapperOfNode(node); if (node.declarations != null) { - for (var i = 0; i < node.declarations.length; i++) { + for (let i = 0; i < node.declarations.length; i++) { if (node.declarations[i] != null) { - var declarationsWrapper = globals.getWrapperOfNode(node.declarations[i]); - try { - variableDeclarationWrapper.addDeclarations(declarationsWrapper); - } catch (e) { - console.error("VARIABLEDECLARATION - Could not add declaration! Reason of the error: " + e + "\n"); - } + globals.safeSet(variableDeclarationWrapper, "addDeclarations", node.declarations[i], "VARIABLEDECLARATION - Could not add declaration!"); } } } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/declaration/variableDeclarator.js b/javascript/cl/JSAN/src/ast/declaration/variableDeclarator.js index 45a52b1..4a12eee 100644 --- a/javascript/cl/JSAN/src/ast/declaration/variableDeclarator.js +++ b/javascript/cl/JSAN/src/ast/declaration/variableDeclarator.js @@ -18,39 +18,29 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var variableDeclarator = factory.createVariableDeclaratorWrapper(); + const variableDeclarator = factory.createVariableDeclaratorWrapper(); globals.setPositionInfo(node, variableDeclarator); - return variableDeclarator; } else { - var variableDeclaratorWrapper = globals.getWrapperOfNode(node); + const variableDeclaratorWrapper = globals.getWrapperOfNode(node); if (node.init != null) { - var initWrapper = globals.getWrapperOfNode(node.init); - try { - variableDeclaratorWrapper.setInit(initWrapper); - } catch (e) { - console.error("VARIABLEDECLARATOR - Could not set init! Reason of the error: " + e + "\n"); - } + globals.safeSet(variableDeclaratorWrapper, "setInit", node.init, "VARIABLEDECLARATOR - Could not set init!"); } if (node.id != null) { - var identifierWrapper = globals.getWrapperOfNode(node.id); - try { - variableDeclaratorWrapper.setIdentifier(identifierWrapper); - } catch (e) { - console.error("VARIABLEDECLARATOR - Could not set identifier! Reason of the error: " + e + "\n"); - } + globals.safeSet(variableDeclaratorWrapper, "setIdentifier", node.id, "VARIABLEDECLARATOR - Could not set identifier!"); } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/arrayExpression.js b/javascript/cl/JSAN/src/ast/expression/arrayExpression.js index 21d1eed..4db817f 100644 --- a/javascript/cl/JSAN/src/ast/expression/arrayExpression.js +++ b/javascript/cl/JSAN/src/ast/expression/arrayExpression.js @@ -18,30 +18,26 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var arrayExpression = factory.createArrayExpressionWrapper(); + const arrayExpression = factory.createArrayExpressionWrapper(); globals.setPositionInfo(node, arrayExpression); return arrayExpression; } else { - var arrayExpressionWrapper = globals.getWrapperOfNode(node); + const arrayExpressionWrapper = globals.getWrapperOfNode(node); if (node.elements != null) { - for (var i = 0; i < node.elements.length; i++) { + for (let i = 0; i < node.elements.length; i++) { if (node.elements[i] != null) { - var elementsWrapper = globals.getWrapperOfNode(node.elements[i]); - try { - arrayExpressionWrapper.addElements(elementsWrapper); - } catch (e) { - console.error("ARRAYEXPRESSION - Could not add element! Reason of the error: " + e + "\n"); - } + globals.safeSet(arrayExpressionWrapper, "addElements", node.elements[i], "ARRAYEXPRESSION - Could not add element!"); } } } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/arrowFunctionExpression.js b/javascript/cl/JSAN/src/ast/expression/arrowFunctionExpression.js index bb5989b..1db9d8b 100644 --- a/javascript/cl/JSAN/src/ast/expression/arrowFunctionExpression.js +++ b/javascript/cl/JSAN/src/ast/expression/arrowFunctionExpression.js @@ -18,53 +18,38 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var arrowFunctionExpression = factory.createArrowFunctionExpressionWrapper(factory); + const arrowFunctionExpression = factory.createArrowFunctionExpressionWrapper(); globals.setPositionInfo(node, arrowFunctionExpression); arrowFunctionExpression.setExpression(node.expression); arrowFunctionExpression.setGenerator(node.generator); arrowFunctionExpression.setAsync(node.async); return arrowFunctionExpression; } else { - var arrowFunctionExpressionWrapper = globals.getWrapperOfNode(node); + const arrowFunctionExpressionWrapper = globals.getWrapperOfNode(node); if (node.params != null) { - for (var i = 0; i < node.params.length; i++) { + for (let i = 0; i < node.params.length; i++) { if (node.params[i] != null) { - var paramsWrapper = globals.getWrapperOfNode(node.params[i]); - try { - arrowFunctionExpressionWrapper.addParams(paramsWrapper); - } catch (e) { - console.error("ARROWFUNCTIONEXPRESSION - Could not add param! Reason of the error: " + e + "\n"); - } + globals.safeSet(arrowFunctionExpressionWrapper, "addParams", node.params[i], "ARROWFUNCTIONEXPRESSION - Could not add param!"); } } } if (node.body != null) { - var bodyWrapper = globals.getWrapperOfNode(node.body); - try { - arrowFunctionExpressionWrapper.setBody(bodyWrapper); - } catch (e) { - console.error("ARROWFUNCTIONEXPRESSION - Could not set body! Reason of the error: " + e + "\n"); - } + globals.safeSet(arrowFunctionExpressionWrapper, "setBody", node.body, "ARROWFUNCTIONEXPRESSION - Could not set body!"); } if (node.id != null) { - var identifierWrapper = globals.getWrapperOfNode(node.id); - try { - arrowFunctionExpressionWrapper.setIdentifier(identifierWrapper); - } catch (e) { - console.error("ARROWFUNCTIONEXPRESSION - Could not set identifier! Reason of the error: " + e + "\n"); - } + globals.safeSet(arrowFunctionExpressionWrapper, "setIdentifier", node.id, "ARROWFUNCTIONEXPRESSION - Could not set identifier!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/assignmentExpression.js b/javascript/cl/JSAN/src/ast/expression/assignmentExpression.js index 77a164b..8c7d6ca 100644 --- a/javascript/cl/JSAN/src/ast/expression/assignmentExpression.js +++ b/javascript/cl/JSAN/src/ast/expression/assignmentExpression.js @@ -18,39 +18,29 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); -const conversions = require('../conversions'); +import * as globals from '../../globals.js'; +import * as conversions from '../conversions.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var assignmentExpression = factory.createAssignmentExpressionWrapper(); + const assignmentExpression = factory.createAssignmentExpressionWrapper(); globals.setPositionInfo(node, assignmentExpression); assignmentExpression.setOperator(conversions.convertOperatorToString(node.operator)); return assignmentExpression; } else { - var assignmentExpressionWrapper = globals.getWrapperOfNode(node); + const assignmentExpressionWrapper = globals.getWrapperOfNode(node); if (node.left != null) { - var leftWrapper = globals.getWrapperOfNode(node.left); - try { - assignmentExpressionWrapper.setLeft(leftWrapper); - } catch (e) { - console.error("ASSIGNMENTEXPRESSION - Could not set left! Reason of the error: " + e + "\n"); - } + globals.safeSet(assignmentExpressionWrapper, "setLeft", node.left, "ASSIGNMENTEXPRESSION - Could not set left!"); } if (node.right != null) { - var rightWrapper = globals.getWrapperOfNode(node.right); - try { - assignmentExpressionWrapper.setRight(rightWrapper); - } catch (e) { - console.error("ASSIGNMENTEXPRESSION - Could not set right! Reason of the error: " + e + "\n"); - } + globals.safeSet(assignmentExpressionWrapper, "setRight", node.right, "ASSIGNMENTEXPRESSION - Could not set right!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/awaitExpression.js b/javascript/cl/JSAN/src/ast/expression/awaitExpression.js index 830e61e..df5204d 100644 --- a/javascript/cl/JSAN/src/ast/expression/awaitExpression.js +++ b/javascript/cl/JSAN/src/ast/expression/awaitExpression.js @@ -18,28 +18,23 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var awaitExpr = factory.createAwaitExpressionWrapper(); + const awaitExpr = factory.createAwaitExpressionWrapper(); globals.setPositionInfo(node, awaitExpr); return awaitExpr; } else { - var awaitExprWrapper = globals.getWrapperOfNode(node); + const awaitExprWrapper = globals.getWrapperOfNode(node); if (node.argument != null) { - var argumentWrapper = globals.getWrapperOfNode(node.argument); - try { - awaitExprWrapper.setArgument(argumentWrapper); - } catch (e) { - console.error("SPREADELEMENT - Could not set argument! Reason of the error: " + e + "\n"); - } + globals.safeSet(awaitExprWrapper, "setArgument", node.argument, "AWAITEXPRESSION - Could not set argument!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/binaryExpression.js b/javascript/cl/JSAN/src/ast/expression/binaryExpression.js index 6d040a6..6155d51 100644 --- a/javascript/cl/JSAN/src/ast/expression/binaryExpression.js +++ b/javascript/cl/JSAN/src/ast/expression/binaryExpression.js @@ -18,39 +18,30 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); -const conversions = require('../conversions'); +import * as globals from '../../globals.js'; +import * as conversions from '../conversions.js' -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var binaryExpression = factory.createBinaryExpressionWrapper(); + const binaryExpression = factory.createBinaryExpressionWrapper(); globals.setPositionInfo(node, binaryExpression); binaryExpression.setOperator(conversions.convertOperatorToString(node.operator)); return binaryExpression; } else { - var binaryExpressionWrapper = globals.getWrapperOfNode(node); + const binaryExpressionWrapper = globals.getWrapperOfNode(node); if (node.left != null) { - var leftWrapper = globals.getWrapperOfNode(node.left); - try { - binaryExpressionWrapper.setLeft(leftWrapper); - } catch (e) { - console.error("BINARYEXPRESSION - Could not set left! Reason of the error: " + e + "\n"); - } + globals.safeSet(binaryExpressionWrapper, "setLeft", node.left, "BINARYEXPRESSION - Could not set left!"); } if (node.right != null) { - var rightWrapper = globals.getWrapperOfNode(node.right); - try { - binaryExpressionWrapper.setRight(rightWrapper); - } catch (e) { - console.error("BINARYEXPRESSION - Could not set right! Reason of the error: " + e + "\n"); - } + globals.safeSet(binaryExpressionWrapper, "setRight", node.right, "BINARYEXPRESSION - Could not set right!"); } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/callExpression.js b/javascript/cl/JSAN/src/ast/expression/callExpression.js index a4ba4c4..28fac39 100644 --- a/javascript/cl/JSAN/src/ast/expression/callExpression.js +++ b/javascript/cl/JSAN/src/ast/expression/callExpression.js @@ -18,41 +18,32 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var callExpression = factory.createCallExpressionWrapper(); + const callExpression = factory.createCallExpressionWrapper(); globals.setPositionInfo(node, callExpression); return callExpression; } else { - var callExpressionWrapper = globals.getWrapperOfNode(node); + const callExpressionWrapper = globals.getWrapperOfNode(node); if (node.callee != null) { - var calleeWrapper = globals.getWrapperOfNode(node.callee); - try { - callExpressionWrapper.setCallee(calleeWrapper); - } catch (e) { - console.error("CALLEXPRESSION - Could not set callee! Reason of the error: " + e + "\n"); - } + globals.safeSet(callExpressionWrapper, "setCallee", node.callee, "CALLEXPRESSION - Could not set callee!"); } if (node.arguments != null) { - for (var i = 0; i < node.arguments.length; i++) { + for (let i = 0; i < node.arguments.length; i++) { if (node.arguments[i] != null) { - var argumentsWrapper = globals.getWrapperOfNode(node.arguments[i]); - try { - callExpressionWrapper.addArguments(argumentsWrapper); - } catch (e) { - console.error("CALLEXPRESSION - Could not add argument! Reason of the error: " + e + "\n"); - } + globals.safeSet(callExpressionWrapper, "addArguments", node.arguments[i], "CALLEXPRESSION - Could not add argument!"); } } } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/chainExpression.js b/javascript/cl/JSAN/src/ast/expression/chainExpression.js new file mode 100644 index 0000000..68a0f99 --- /dev/null +++ b/javascript/cl/JSAN/src/ast/expression/chainExpression.js @@ -0,0 +1,20 @@ +import * as globals from '../../globals.js'; + +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { + if (firstVisit) { + if (globals.getWrapperOfNode(node) !== undefined) { + return; + } + let chainExpression = factory.createChainExpressionWrapper(); + globals.setPositionInfo(node, chainExpression); + return chainExpression; + } else { + let chainExpressionWrapper = globals.getWrapperOfNode(node); + + if (node.expression != null) { + globals.safeSet(chainExpressionWrapper, "setExpression", node.expression, "CHAINEXPRESSION - Could not set expression!"); + } + } +} diff --git a/javascript/cl/JSAN/src/ast/expression/classExpression.js b/javascript/cl/JSAN/src/ast/expression/classExpression.js index 09eabde..7ab72a6 100644 --- a/javascript/cl/JSAN/src/ast/expression/classExpression.js +++ b/javascript/cl/JSAN/src/ast/expression/classExpression.js @@ -18,47 +18,31 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var classExpression = factory.createClassExpressionWrapper(); + const classExpression = factory.createClassExpressionWrapper(); globals.setPositionInfo(node, classExpression); return classExpression; } else { - var classExpressionWrapper = globals.getWrapperOfNode(node); - + const classExpressionWrapper = globals.getWrapperOfNode(node); if (node.superClass != null) { - var superClassWrapper = globals.getWrapperOfNode(node.superClass); - try { - classExpressionWrapper.setSuperClass(superClassWrapper); - } catch (e) { - console.error("CLASSEXPRESSION - Could not set superclass! Reason of the error: " + e + "\n"); - } + globals.safeSet(classExpressionWrapper, "setSuperClass", node.superClass, "CLASSEXPRESSION - Could not set superclass!"); } if (node.id != null) { - var identifierWrapper = globals.getWrapperOfNode(node.id); - try { - classExpressionWrapper.setIdentifier(identifierWrapper); - } catch (e) { - console.error("CLASSEXPRESSION - Could not set identifier! Reason of the error: " + e + "\n"); - } + globals.safeSet(classExpressionWrapper, "setIdentifier", node.id, "CLASSEXPRESSION - Could not set identifier!"); } if (node.body != null) { - var bodyWrapper = globals.getWrapperOfNode(node.body); - try { - classExpressionWrapper.setBody(bodyWrapper); - } catch (e) { - console.error("CLASSEXPRESSION - Could not set body! Reason of the error: " + e + "\n"); - } + globals.safeSet(classExpressionWrapper, "setBody", node.body, "CLASSEXPRESSION - Could not set body!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/conditionalExpression.js b/javascript/cl/JSAN/src/ast/expression/conditionalExpression.js index 41fbe64..2285078 100644 --- a/javascript/cl/JSAN/src/ast/expression/conditionalExpression.js +++ b/javascript/cl/JSAN/src/ast/expression/conditionalExpression.js @@ -18,46 +18,31 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var conditionalExpression = factory.createConditionalExpressionWrapper(); + const conditionalExpression = factory.createConditionalExpressionWrapper(); globals.setPositionInfo(node, conditionalExpression); return conditionalExpression; } else { - var conditionalExpressionWrapper = globals.getWrapperOfNode(node); + const conditionalExpressionWrapper = globals.getWrapperOfNode(node); if (node.alternate != null) { - var alternateWrapper = globals.getWrapperOfNode(node.alternate); - try { - conditionalExpressionWrapper.setAlternate(alternateWrapper); - } catch (e) { - console.error("CONDITIONALEXPRESSION - Could not set alternate! Reason of the error: " + e + "\n"); - } + globals.safeSet(conditionalExpressionWrapper, "setAlternate", node.alternate, "CONDITIONALEXPRESSION - Could not set alternate!"); } if (node.test != null) { - var testWrapper = globals.getWrapperOfNode(node.test); - try { - conditionalExpressionWrapper.setTest(testWrapper); - } catch (e) { - console.error("CONDITIONALEXPRESSION - Could not set test! Reason of the error: " + e + "\n"); - } + globals.safeSet(conditionalExpressionWrapper, "setTest", node.test, "CONDITIONALEXPRESSION - Could not set test!"); } if (node.consequent != null) { - var consequentWrapper = globals.getWrapperOfNode(node.consequent); - try { - conditionalExpressionWrapper.setConsequent(consequentWrapper); - } catch (e) { - console.error("CONDITIONALEXPRESSION - Could not set consequent! Reason of the error: " + e + "\n"); - } + globals.safeSet(conditionalExpressionWrapper, "setConsequent", node.consequent, "CONDITIONALEXPRESSION - Could not set consequent!") } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/functionExpression.js b/javascript/cl/JSAN/src/ast/expression/functionExpression.js index 108ff1d..ec870c5 100644 --- a/javascript/cl/JSAN/src/ast/expression/functionExpression.js +++ b/javascript/cl/JSAN/src/ast/expression/functionExpression.js @@ -18,53 +18,39 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var functionExpression = factory.createFunctionExpressionWrapper(); + const functionExpression = factory.createFunctionExpressionWrapper(); globals.setPositionInfo(node, functionExpression); functionExpression.setGenerator(node.generator); functionExpression.setExpression(node.expression); functionExpression.setAsync(node.async); return functionExpression; } else { - var functionExpressionWrapper = globals.getWrapperOfNode(node); + const functionExpressionWrapper = globals.getWrapperOfNode(node); if (node.params != null) { - for (var i = 0; i < node.params.length; i++) { + for (let i = 0; i < node.params.length; i++) { if (node.params[i] != null) { - var paramsWrapper = globals.getWrapperOfNode(node.params[i]); - try { - functionExpressionWrapper.addParams(paramsWrapper); - } catch (e) { - console.error("FUNCTIONEXPRESSION - Could not add params! Reason of the error: " + e + "\n"); - } + globals.safeSet(functionExpressionWrapper, "addParams", node.params[i], "FUNCTIONEXPRESSION - Could not add params!"); } } } if (node.body != null) { - var bodyWrapper = globals.getWrapperOfNode(node.body); - try { - functionExpressionWrapper.setBody(bodyWrapper); - } catch (e) { - console.error("FUNCTIONEXPRESSION - Could not set body! Reason of the error: " + e + "\n"); - } + globals.safeSet(functionExpressionWrapper, "setBody", node.body, "FUNCTIONEXPRESSION - Could not set body!"); } if (node.id != null) { - var identifierWrapper = globals.getWrapperOfNode(node.id); - try { - functionExpressionWrapper.setIdentifier(identifierWrapper); - } catch (e) { - console.error("FUNCTIONEXPRESSION - Could not set identifier! Reason of the error: " + e + "\n"); - } + globals.safeSet(functionExpressionWrapper, "setIdentifier", node.id, "FUNCTIONEXPRESSION - Could not set identifier!") } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/identifier.js b/javascript/cl/JSAN/src/ast/expression/identifier.js index ba678ac..6a67883 100644 --- a/javascript/cl/JSAN/src/ast/expression/identifier.js +++ b/javascript/cl/JSAN/src/ast/expression/identifier.js @@ -18,17 +18,18 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var identifier = factory.createIdentifierWrapper(); + const identifier = factory.createIdentifierWrapper(); globals.setPositionInfo(node, identifier); identifier.setName(node.name); return identifier; } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/importExpression.js b/javascript/cl/JSAN/src/ast/expression/importExpression.js new file mode 100644 index 0000000..d21c505 --- /dev/null +++ b/javascript/cl/JSAN/src/ast/expression/importExpression.js @@ -0,0 +1,20 @@ +import * as globals from '../../globals.js'; + +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { + if (firstVisit) { + if (globals.getWrapperOfNode(node) !== undefined) { + return; + } + const importExpression = factory.createImportExpressionWrapper(); + globals.setPositionInfo(node, importExpression); + return importExpression; + } else { + const importExpressionWrapper = globals.getWrapperOfNode(node); + + if (node.source != null) { + globals.safeSet(importExpressionWrapper, "setSource", node.source, "IMPORTEXPRESSION - Could not set source!"); + } + } +} diff --git a/javascript/cl/JSAN/src/ast/expression/literal.js b/javascript/cl/JSAN/src/ast/expression/literal.js index d50f00f..7bb1a1d 100644 --- a/javascript/cl/JSAN/src/ast/expression/literal.js +++ b/javascript/cl/JSAN/src/ast/expression/literal.js @@ -18,18 +18,18 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { - if (firstVisit) { - var type = globals.getLiteralType(node); - var literalNode; +const factory = globals.getFactory(); +export default function (node, parent, firstVisit) { + if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } + const type = globals.getLiteralType(node); + let literalNode; switch (type) { case "Number": literalNode = factory.createNumberLiteralWrapper(); @@ -51,9 +51,12 @@ module.exports = function (node, parent, firstVisit) { literalNode.setFlags(node.regex.flags); literalNode.setPattern(node.regex.pattern); break; + case "Bigint": + literalNode = factory.createBigIntLiteralWrapper(); + literalNode.setBigint(node.bigint); + break; default: - console.log("Literal type not recognized! Type: " + type); - return; + throw new Error("Literal type could not be recognized! Type: " + type); } globals.setPositionInfo(node, literalNode); @@ -62,4 +65,4 @@ module.exports = function (node, parent, firstVisit) { return literalNode; } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/logicalExpression.js b/javascript/cl/JSAN/src/ast/expression/logicalExpression.js index 372ac39..79fd580 100644 --- a/javascript/cl/JSAN/src/ast/expression/logicalExpression.js +++ b/javascript/cl/JSAN/src/ast/expression/logicalExpression.js @@ -18,39 +18,29 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); -const conversions = require('../conversions'); +import * as globals from '../../globals.js'; +import * as conversions from '../conversions.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var logicalExpression = factory.createLogicalExpressionWrapper(factory); + const logicalExpression = factory.createLogicalExpressionWrapper(); globals.setPositionInfo(node, logicalExpression); logicalExpression.setOperator(conversions.convertOperatorToString(node.operator)); return logicalExpression; } else { - var logicalExpressionWrapper = globals.getWrapperOfNode(node); + const logicalExpressionWrapper = globals.getWrapperOfNode(node); if (node.left != null) { - var leftWrapper = globals.getWrapperOfNode(node.left); - try { - logicalExpressionWrapper.setLeft(leftWrapper); - } catch (e) { - console.error("LOGICALEXPRESSION - Could not set left! Reason of the error: " + e + "\n"); - } + globals.safeSet(logicalExpressionWrapper, "setLeft", node.left, "LOGICALEXPRESSION - Could not set left!"); } if (node.right != null) { - var rightWrapper = globals.getWrapperOfNode(node.right); - try { - logicalExpressionWrapper.setRight(rightWrapper); - } catch (e) { - console.error("LOGICALEXPRESSION - Could not set right! Reason of the error: " + e + "\n"); - } + globals.safeSet(logicalExpressionWrapper, "setRight", node.right, "LOGICALEXPRESSION - Could not set right!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/memberExpression.js b/javascript/cl/JSAN/src/ast/expression/memberExpression.js index be0e028..6e930e5 100644 --- a/javascript/cl/JSAN/src/ast/expression/memberExpression.js +++ b/javascript/cl/JSAN/src/ast/expression/memberExpression.js @@ -18,38 +18,29 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var memberExpression = factory.createMemberExpressionWrapper(); + const memberExpression = factory.createMemberExpressionWrapper(); globals.setPositionInfo(node, memberExpression); memberExpression.setComputed(node.computed); return memberExpression; } else { - var memberExpressionWrapper = globals.getWrapperOfNode(node); + const memberExpressionWrapper = globals.getWrapperOfNode(node); if (node.property != null) { - var propertyWrapper = globals.getWrapperOfNode(node.property); - try { - memberExpressionWrapper.setProperty(propertyWrapper); - } catch (e) { - console.error("MEMBEREXPRESSION - Could not set property! Reason of the error: " + e + "\n"); - } + globals.safeSet(memberExpressionWrapper, "setProperty", node.property, "MEMBEREXPRESSION - Could not set property!"); } if (node.object != null) { - var objectWrapper = globals.getWrapperOfNode(node.object); - try { - memberExpressionWrapper.setObject(objectWrapper); - } catch (e) { - console.error("MEMBEREXPRESSION - Could not set object! Reason of the error: " + e + "\n"); - } + globals.safeSet(memberExpressionWrapper, "setObject", node.object, "MEMBEREXPRESSION - Could not set object!"); } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/metaProperty.js b/javascript/cl/JSAN/src/ast/expression/metaProperty.js index b7820ed..2f4b9af 100644 --- a/javascript/cl/JSAN/src/ast/expression/metaProperty.js +++ b/javascript/cl/JSAN/src/ast/expression/metaProperty.js @@ -18,37 +18,28 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var metaProperty = factory.createMetaPropertyWrapper(); + const metaProperty = factory.createMetaPropertyWrapper(); globals.setPositionInfo(node, metaProperty); return metaProperty; } else { - var metaPropertyWrapper = globals.getWrapperOfNode(node); + const metaPropertyWrapper = globals.getWrapperOfNode(node); if (node.meta != null) { - var metaWrapper = globals.getWrapperOfNode(node.meta); - try { - metaPropertyWrapper.setMeta(metaWrapper); - } catch (e) { - console.error("METAPROPERTY - Could not set meta! Reason of the error: " + e + "\n"); - } + globals.safeSet(metaPropertyWrapper, "setMeta", node.meta, "METAPROPERTY - Could not set meta!"); } if (node.property != null) { - var propertyWrapper = globals.getWrapperOfNode(node.property); - try { - metaPropertyWrapper.setProperty(propertyWrapper); - } catch (e) { - console.error("METAPROPERTY - Could not set property! Reason of the error: " + e + "\n"); - } + globals.safeSet(metaPropertyWrapper, "setProperty", node.property, "METAPROPERTY - Could not set property!"); } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/newExpression.js b/javascript/cl/JSAN/src/ast/expression/newExpression.js index 5776ff3..008a132 100644 --- a/javascript/cl/JSAN/src/ast/expression/newExpression.js +++ b/javascript/cl/JSAN/src/ast/expression/newExpression.js @@ -18,40 +18,31 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var newExpression = factory.createNewExpressionWrapper(); + const newExpression = factory.createNewExpressionWrapper(); globals.setPositionInfo(node, newExpression); return newExpression; } else { - var newExpressionWrapper = globals.getWrapperOfNode(node); + const newExpressionWrapper = globals.getWrapperOfNode(node); if (node.callee != null) { - var calleeWrapper = globals.getWrapperOfNode(node.callee); - try { - newExpressionWrapper.setCallee(calleeWrapper); - } catch (e) { - console.error("NEWEXPRESSION - Could not set callee! Reason of the error: " + e + "\n"); - } + globals.safeSet(newExpressionWrapper, "setCallee", node.callee, "NEWEXPRESSION - Could not set callee!"); } if (node.arguments != null) { - for (var i = 0; i < node.arguments.length; i++) { + for (let i = 0; i < node.arguments.length; i++) { if (node.arguments[i] != null) { - var argumentsWrapper = globals.getWrapperOfNode(node.arguments[i]); - try { - newExpressionWrapper.addArguments(argumentsWrapper); - } catch (e) { - console.error("NEWEXPRESSION - Could not add argument! Reason of the error: " + e + "\n"); - } + globals.safeSet(newExpressionWrapper, "addArguments", node.arguments[i], "NEWEXPRESSION - Could not set argument!"); } } } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/objectExpression.js b/javascript/cl/JSAN/src/ast/expression/objectExpression.js index 4b962f6..6b85d08 100644 --- a/javascript/cl/JSAN/src/ast/expression/objectExpression.js +++ b/javascript/cl/JSAN/src/ast/expression/objectExpression.js @@ -18,30 +18,26 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var objectExpression = factory.createObjectExpressionWrapper(); + const objectExpression = factory.createObjectExpressionWrapper(); globals.setPositionInfo(node, objectExpression); return objectExpression; } else { - var objectExpressionWrapper = globals.getWrapperOfNode(node); + const objectExpressionWrapper = globals.getWrapperOfNode(node); if (node.properties != null) { - for (var i = 0; i < node.properties.length; i++) { + for (let i = 0; i < node.properties.length; i++) { if (node.properties[i] != null) { - var propertiesWrapper = globals.getWrapperOfNode(node.properties[i]); - try { - objectExpressionWrapper.addProperties(propertiesWrapper); - } catch (e) { - console.error("OBJECTEXPRESSION - Could not add property! Reason of the error: " + e + "\n"); - } + globals.safeSet(objectExpressionWrapper, "addProperties", node.properties[i], "OBJECTEXPRESSION - Could not add property!"); } } } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/privateIdentifier.js b/javascript/cl/JSAN/src/ast/expression/privateIdentifier.js new file mode 100644 index 0000000..095e950 --- /dev/null +++ b/javascript/cl/JSAN/src/ast/expression/privateIdentifier.js @@ -0,0 +1,22 @@ +import * as globals from '../../globals.js'; + +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { + if (firstVisit) { + if (globals.getWrapperOfNode(node) !== undefined) { + return; + } + const privateIdentifier = factory.createPrivateIdentifierWrapper(); + globals.setPositionInfo(node, privateIdentifier); + + // Workaround until parser gets updated + // TODO: Remove this once parser gets updated + if (node.type === 'TSPrivateIdentifier') { + privateIdentifier.setName(node.escapedText.substring(1)); + } else { + privateIdentifier.setName(node.name); + } + return privateIdentifier; + } +} diff --git a/javascript/cl/JSAN/src/ast/expression/property.js b/javascript/cl/JSAN/src/ast/expression/property.js index 3150a7c..5e7b7fc 100644 --- a/javascript/cl/JSAN/src/ast/expression/property.js +++ b/javascript/cl/JSAN/src/ast/expression/property.js @@ -18,16 +18,17 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); -const conversions = require('../conversions'); +import * as globals from '../../globals.js'; +import * as conversions from '../conversions.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var property = factory.createPropertyWrapper(); + const property = factory.createPropertyWrapper(); globals.setPositionInfo(node, property); property.setKind(conversions.convertPropertyKind(node.kind)); property.setMethod(node.method); @@ -35,25 +36,15 @@ module.exports = function (node, parent, firstVisit) { property.setComputed(node.computed); return property; } else { - var propertyWrapper = globals.getWrapperOfNode(node); + const propertyWrapper = globals.getWrapperOfNode(node); if (node.key != null) { - var keyWrapper = globals.getWrapperOfNode(node.key); - try { - propertyWrapper.setKey(keyWrapper); - } catch (e) { - console.error("PROPERTY - Could not set key! Reason of the error: " + e + "\n"); - } + globals.safeSet(propertyWrapper, "setKey", node.key, "PROPERTY - Could not set key!"); } if (node.value != null) { - var valueWrapper = globals.getWrapperOfNode(node.value); - try { - propertyWrapper.setValue(valueWrapper); - } catch (e) { - console.error("PROPERTY - Could not set value! Reason of the error: " + e + "\n"); - } + globals.safeSet(propertyWrapper, "setValue", node.value, "PROPERTY - Could not set value!"); } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/regExpLiteral.js b/javascript/cl/JSAN/src/ast/expression/regExpLiteral.js index 6344a04..4e45790 100644 --- a/javascript/cl/JSAN/src/ast/expression/regExpLiteral.js +++ b/javascript/cl/JSAN/src/ast/expression/regExpLiteral.js @@ -18,18 +18,19 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var regExpLiteral = factory.createRegExpLiteralWrapper(); + const regExpLiteral = factory.createRegExpLiteralWrapper(); globals.setPositionInfo(node, regExpLiteral); regExpLiteral.setPattern(node.pattern); regExpLiteral.setFlags(node.flags); return regExpLiteral; } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/sequenceExpression.js b/javascript/cl/JSAN/src/ast/expression/sequenceExpression.js index d0f2346..de8fa29 100644 --- a/javascript/cl/JSAN/src/ast/expression/sequenceExpression.js +++ b/javascript/cl/JSAN/src/ast/expression/sequenceExpression.js @@ -18,31 +18,26 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; +const factory = globals.getFactory(); -module.exports = function (node, parent, firstVisit) { +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var sequenceExpression = factory.createSequenceExpressionWrapper(); + const sequenceExpression = factory.createSequenceExpressionWrapper(); globals.setPositionInfo(node, sequenceExpression); return sequenceExpression; } else { - var sequenceExpressionWrapper = globals.getWrapperOfNode(node); + const sequenceExpressionWrapper = globals.getWrapperOfNode(node); if (node.expressions != null) { - for (var i = 0; i < node.expressions.length; i++) { + for (let i = 0; i < node.expressions.length; i++) { if (node.expressions[i] != null) { - var expressionsWrapper = globals.getWrapperOfNode(node.expressions[i]); - try { - sequenceExpressionWrapper.addExpressions(expressionsWrapper); - } catch (e) { - console.error("SEQUENCEEXPRESSION - Could not add expression! Reason of the error: " + e + "\n"); - } + globals.safeSet(sequenceExpressionWrapper, "addExpressions", node.expressions[i], "SEQUENCEEXPRESSION - Could not add expression!"); } } } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/spreadElement.js b/javascript/cl/JSAN/src/ast/expression/spreadElement.js index 7536560..58197ae 100644 --- a/javascript/cl/JSAN/src/ast/expression/spreadElement.js +++ b/javascript/cl/JSAN/src/ast/expression/spreadElement.js @@ -18,28 +18,23 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var spreadElement = factory.createSpreadElementWrapper(); + const spreadElement = factory.createSpreadElementWrapper(); globals.setPositionInfo(node, spreadElement); return spreadElement; } else { - var spreadElementWrapper = globals.getWrapperOfNode(node); + const spreadElementWrapper = globals.getWrapperOfNode(node); if (node.argument != null) { - var argumentWrapper = globals.getWrapperOfNode(node.argument); - try { - spreadElementWrapper.setArgument(argumentWrapper); - } catch (e) { - console.error("SPREADELEMENT - Could not add argument! Reason of the error: " + e + "\n"); - } + globals.safeSet(spreadElementWrapper, "setArgument", node.argument, "SPREADELEMENT - Could not add argument!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/super.js b/javascript/cl/JSAN/src/ast/expression/super.js index e292a0a..230bfdb 100644 --- a/javascript/cl/JSAN/src/ast/expression/super.js +++ b/javascript/cl/JSAN/src/ast/expression/super.js @@ -18,16 +18,17 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var superNode = factory.createSuperWrapper(); + const superNode = factory.createSuperWrapper(); globals.setPositionInfo(node, superNode); return superNode; } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/taggedTemplateExpression.js b/javascript/cl/JSAN/src/ast/expression/taggedTemplateExpression.js index 7495387..164b97b 100644 --- a/javascript/cl/JSAN/src/ast/expression/taggedTemplateExpression.js +++ b/javascript/cl/JSAN/src/ast/expression/taggedTemplateExpression.js @@ -18,37 +18,27 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var taggedTemplateExpression = factory.createTaggedTemplateExpressionWrapper(); + const taggedTemplateExpression = factory.createTaggedTemplateExpressionWrapper(); globals.setPositionInfo(node, taggedTemplateExpression); return taggedTemplateExpression; } else { - var taggedTemplateExpressionWrapper = globals.getWrapperOfNode(node); + const taggedTemplateExpressionWrapper = globals.getWrapperOfNode(node); if (node.tag != null) { - var tagWrapper = globals.getWrapperOfNode(node.tag); - try { - taggedTemplateExpressionWrapper.setTag(tagWrapper); - } catch (e) { - console.error("TAGGEDTEMPLATEEXPRESSION - Could not add tag! Reason of the error: " + e + "\n"); - } + globals.safeSet(taggedTemplateExpressionWrapper, "setTag", node.tag, "TAGGEDTEMPLATEEXPRESSION - Could not add tag!"); } if (node.quasi != null) { - var quasiWrapper = globals.getWrapperOfNode(node.quasi); - try { - taggedTemplateExpressionWrapper.setQuasi(quasiWrapper); - } catch (e) { - console.error("TAGGEDTEMPLATEEXPRESSION - Could not set quasi! Reason of the error: " + e + "\n"); - } + globals.safeSet(taggedTemplateExpressionWrapper, "setQuasi", node.quasi, "TAGGEDTEMPLATEEXPRESSION - Could not set quasi!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/templateElement.js b/javascript/cl/JSAN/src/ast/expression/templateElement.js index dab295b..1511f3b 100644 --- a/javascript/cl/JSAN/src/ast/expression/templateElement.js +++ b/javascript/cl/JSAN/src/ast/expression/templateElement.js @@ -18,19 +18,20 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var templateElement = factory.createTemplateElementWrapper(); + const templateElement = factory.createTemplateElementWrapper(); globals.setPositionInfo(node, templateElement); templateElement.setTail(node.tail); templateElement.setCooked(node.value.cooked); templateElement.setValue(node.value.raw); return templateElement; } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/templateLiteral.js b/javascript/cl/JSAN/src/ast/expression/templateLiteral.js index 167dbea..3a8beb7 100644 --- a/javascript/cl/JSAN/src/ast/expression/templateLiteral.js +++ b/javascript/cl/JSAN/src/ast/expression/templateLiteral.js @@ -18,52 +18,39 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var templateLiteral = factory.createTemplateLiteralWrapper(); + const templateLiteral = factory.createTemplateLiteralWrapper(); globals.setPositionInfo(node, templateLiteral); return templateLiteral; } else { - var templateLiteralWrapper = globals.getWrapperOfNode(node); + const templateLiteralWrapper = globals.getWrapperOfNode(node); if (node.quasi != null) { - var quasiWrapper = globals.getWrapperOfNode(node.quasi); - try { - templateLiteralWrapper.setQuasi(quasiWrapper); - } catch (e) { - console.error("TEMPLATELITERAL - Could not set quasi! Reason of the error: " + e + "\n"); - } + globals.safeSet(templateLiteralWrapper, "setQuasi", node.quasi, "TEMPLATELITERAL - Could not set quasi!"); } if (node.expressions != null) { - for (var i = 0; i < node.expressions.length; i++) { + for (let i = 0; i < node.expressions.length; i++) { if (node.expressions[i] != null) { - var expressionsWrapper = globals.getWrapperOfNode(node.expressions[i]); - try { - templateLiteralWrapper.addExpressions(expressionsWrapper); - } catch (e) { - console.error("TEMPLATELITERAL - Could not add expression! Reason of the error: " + e + "\n"); - } + globals.safeSet(templateLiteralWrapper, "addExpressions", node.expressions[i], "TEMPLATELITERAL - Could not add expression!"); } } } + if (node.quasis != null) { - for (var i = 0; i < node.quasis.length; i++) { + for (let i = 0; i < node.quasis.length; i++) { if (node.quasis[i] != null) { - var quasisWrapper = globals.getWrapperOfNode(node.quasis[i]); - try { - templateLiteralWrapper.addQuasis(quasisWrapper); - } catch (e) { - console.error("TEMPLATELITERAL - Could not add quasi! Reason of the error: " + e + "\n"); - } + globals.safeSet(templateLiteralWrapper, "addQuasis", node.quasis[i], "TEMPLATELITERAL - Could not add quasis!"); } } } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/thisExpression.js b/javascript/cl/JSAN/src/ast/expression/thisExpression.js index a0b22c9..7a7e66a 100644 --- a/javascript/cl/JSAN/src/ast/expression/thisExpression.js +++ b/javascript/cl/JSAN/src/ast/expression/thisExpression.js @@ -18,28 +18,23 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var thisExpression = factory.createThisExpressionWrapper(); + const thisExpression = factory.createThisExpressionWrapper(); globals.setPositionInfo(node, thisExpression); return thisExpression; } else { - var thisExpressionWrapper = globals.getWrapperOfNode(node); + const thisExpressionWrapper = globals.getWrapperOfNode(node); if (node.body != null) { - var bodyWrapper = globals.getWrapperOfNode(node.body); - try { - thisExpressionWrapper.setBody(bodyWrapper); - } catch (e) { - console.error("THISEXPRESSION - Could not set body! Reason of the error: " + e + "\n"); - } + globals.safeSet(thisExpressionWrapper, "setBody", node.body, "THISEXPRESSION - Could not set body!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/unaryExpression.js b/javascript/cl/JSAN/src/ast/expression/unaryExpression.js index e7d83aa..d905ccd 100644 --- a/javascript/cl/JSAN/src/ast/expression/unaryExpression.js +++ b/javascript/cl/JSAN/src/ast/expression/unaryExpression.js @@ -18,31 +18,26 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); -var conversions = require('../conversions'); +import * as globals from '../../globals.js'; +import * as conversions from '../conversions.js'; +const factory = globals.getFactory(); -module.exports = function (node, parent, firstVisit) { + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var unaryExpression = factory.createUnaryExpressionWrapper(); + const unaryExpression = factory.createUnaryExpressionWrapper(); globals.setPositionInfo(node, unaryExpression); unaryExpression.setOperator(conversions.convertUnaryOperatorToString(node.operator)); unaryExpression.setPrefix(node.prefix); return unaryExpression; } else { - var unaryExpressionWrapper = globals.getWrapperOfNode(node); + const unaryExpressionWrapper = globals.getWrapperOfNode(node); if (node.argument != null) { - var argumentWrapper = globals.getWrapperOfNode(node.argument); - try { - unaryExpressionWrapper.setArgument(argumentWrapper); - } catch (e) { - console.error("UNARYEXPRESSION - Could not set argument! Reason of the error: " + e + "\n"); - } + globals.safeSet(unaryExpressionWrapper, "setArgument", node.argument, "UNARYEXPRESSION - Could not set argument!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/updateExpression.js b/javascript/cl/JSAN/src/ast/expression/updateExpression.js index daadf3d..5a51896 100644 --- a/javascript/cl/JSAN/src/ast/expression/updateExpression.js +++ b/javascript/cl/JSAN/src/ast/expression/updateExpression.js @@ -18,31 +18,27 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); -const conversions = require('../conversions'); +import * as globals from '../../globals.js'; +import * as conversions from '../conversions.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var updateExpression = factory.createUpdateExpressionWrapper(); + const updateExpression = factory.createUpdateExpressionWrapper(); globals.setPositionInfo(node, updateExpression); updateExpression.setOperator(conversions.convertOperatorToString(node.operator)); updateExpression.setPrefix(node.prefix); return updateExpression; } else { - var updateExpressionWrapper = globals.getWrapperOfNode(node); + const updateExpressionWrapper = globals.getWrapperOfNode(node); if (node.argument != null) { - var argumentWrapper = globals.getWrapperOfNode(node.argument); - try { - updateExpressionWrapper.setArgument(argumentWrapper); - } catch (e) { - console.error("UPDATEEXPRESSION - Could not st argument! Reason of the error: " + e + "\n"); - } + globals.safeSet(updateExpressionWrapper, "setArgument", node.argument, "UPDATEEXPRESSION - Could not set argument!"); } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/expression/yieldExpression.js b/javascript/cl/JSAN/src/ast/expression/yieldExpression.js index 1a7d12b..6bb9ed2 100644 --- a/javascript/cl/JSAN/src/ast/expression/yieldExpression.js +++ b/javascript/cl/JSAN/src/ast/expression/yieldExpression.js @@ -18,29 +18,24 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var yieldExpression = factory.createYieldExpressionWrapper(); + const yieldExpression = factory.createYieldExpressionWrapper(); globals.setPositionInfo(node, yieldExpression); yieldExpression.setDelegate(node.delegate); return yieldExpression; } else { - var yieldExpressionWrapper = globals.getWrapperOfNode(node); + const yieldExpressionWrapper = globals.getWrapperOfNode(node); yieldExpressionWrapper.setDelegate(node.delegate); if (node.argument != null) { - var argumentWrapper = globals.getWrapperOfNode(node.argument); - try { - yieldExpressionWrapper.setArgument(argumentWrapper); - } catch (e) { - console.error("YIELDEXPRESSION - Could not set argument! Reason of the error: " + e + "\n"); - } + globals.safeSet(yieldExpressionWrapper, "setArgument", node.argument, "YIELDEXPRESSION - Could not set argument!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/statement/arrayPattern.js b/javascript/cl/JSAN/src/ast/statement/arrayPattern.js index 46614d5..1a3dc7b 100644 --- a/javascript/cl/JSAN/src/ast/statement/arrayPattern.js +++ b/javascript/cl/JSAN/src/ast/statement/arrayPattern.js @@ -18,30 +18,26 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var arrayPattern = factory.createArrayPatternWrapper(); + const arrayPattern = factory.createArrayPatternWrapper(); globals.setPositionInfo(node, arrayPattern); return arrayPattern; } else { - var arrayPatternWrapper = globals.getWrapperOfNode(node); + const arrayPatternWrapper = globals.getWrapperOfNode(node); if (node.elements != null) { - for (var i = 0; i < node.elements.length; i++) { + for (let i = 0; i < node.elements.length; i++) { if (node.elements[i] != null) { - var elementsWrapper = globals.getWrapperOfNode(node.elements[i]); - try { - arrayPatternWrapper.addElements(elementsWrapper); - } catch (e) { - console.error("ARRAYPATTERN - Could not add element! Reason of the error: " + e + "\n"); - } + globals.safeSet(arrayPatternWrapper, "addElements", node.elements[i], "ARRAYPATTERN - Could not add element!"); } } } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/statement/assignmentPattern.js b/javascript/cl/JSAN/src/ast/statement/assignmentPattern.js index 3f374d3..1bf7636 100644 --- a/javascript/cl/JSAN/src/ast/statement/assignmentPattern.js +++ b/javascript/cl/JSAN/src/ast/statement/assignmentPattern.js @@ -18,37 +18,27 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var assignmentPattern = factory.createAssignmentPatternWrapper(); + const assignmentPattern = factory.createAssignmentPatternWrapper(); globals.setPositionInfo(node, assignmentPattern); return assignmentPattern; } else { - var assignmentPatternWrapper = globals.getWrapperOfNode(node); + const assignmentPatternWrapper = globals.getWrapperOfNode(node); if (node.left != null) { - var leftWrapper = globals.getWrapperOfNode(node.left); - try { - assignmentPatternWrapper.setLeft(leftWrapper); - } catch (e) { - console.error("ASSIGNMENTPATTERN - Could not set left! Reason of the error: " + e + "\n"); - } + globals.safeSet(assignmentPatternWrapper, "setLeft", node.left, "ASSIGNMENTPATTERN - Could not set left!"); } if (node.right != null) { - var rightWrapper = globals.getWrapperOfNode(node.right); - try { - assignmentPatternWrapper.setRight(rightWrapper); - } catch (e) { - console.error("ASSIGNMENTPATTERN - Could not set right! Reason of the error: " + e + "\n"); - } + globals.safeSet(assignmentPatternWrapper, "setRight", node.right, "ASSIGNMENTPATTERN - Could not set right!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/statement/blockStatement.js b/javascript/cl/JSAN/src/ast/statement/blockStatement.js index 1a0c6e5..ad10071 100644 --- a/javascript/cl/JSAN/src/ast/statement/blockStatement.js +++ b/javascript/cl/JSAN/src/ast/statement/blockStatement.js @@ -18,30 +18,26 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var blockStatement = factory.createBlockStatementWrapper(); + const blockStatement = factory.createBlockStatementWrapper(); globals.setPositionInfo(node, blockStatement); return blockStatement; } else { - var blockStatementWrapper = globals.getWrapperOfNode(node); + const blockStatementWrapper = globals.getWrapperOfNode(node); if (node.body != null) { - for (var i = 0; i < node.body.length; i++) { + for (let i = 0; i < node.body.length; i++) { if (node.body[i] != null) { - var bodyWrapper = globals.getWrapperOfNode(node.body[i]); - try { - blockStatementWrapper.addBody(bodyWrapper); - } catch (e) { - console.error("BLOCKSTATEMENT - Could not add body! Reason of the error: " + e + "\n"); - } + globals.safeSet(blockStatementWrapper, "addBody", node.body[i], "BLOCKSTATEMENT - Could not add body!"); } } } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/statement/breakStatement.js b/javascript/cl/JSAN/src/ast/statement/breakStatement.js index 960cf9a..61f47c2 100644 --- a/javascript/cl/JSAN/src/ast/statement/breakStatement.js +++ b/javascript/cl/JSAN/src/ast/statement/breakStatement.js @@ -18,27 +18,22 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var breakStatement = factory.createBreakStatementWrapper(); + const breakStatement = factory.createBreakStatementWrapper(); globals.setPositionInfo(node, breakStatement); return breakStatement; } else { - var breakStatementWrapper = globals.getWrapperOfNode(node); + const breakStatementWrapper = globals.getWrapperOfNode(node); if (node.label != null) { - var labelWrapper = globals.getWrapperOfNode(node.label); - try { - breakStatementWrapper.setLabel(labelWrapper); - } catch (e) { - console.error("BREAKSTATEMENT - Could not set label! Reason of the error: " + e + "\n"); - } + globals.safeSet(breakStatementWrapper, "setLabel", node.label, "BREAKSTATEMENT - Could not set label!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/statement/catchClause.js b/javascript/cl/JSAN/src/ast/statement/catchClause.js index ece9cb1..7d2974f 100644 --- a/javascript/cl/JSAN/src/ast/statement/catchClause.js +++ b/javascript/cl/JSAN/src/ast/statement/catchClause.js @@ -18,37 +18,27 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var catchClause = factory.createCatchClauseWrapper(); + const catchClause = factory.createCatchClauseWrapper(); globals.setPositionInfo(node, catchClause); return catchClause; } else { - var catchClauseWrapper = globals.getWrapperOfNode(node); + const catchClauseWrapper = globals.getWrapperOfNode(node); if (node.body != null) { - var bodyWrapper = globals.getWrapperOfNode(node.body); - try { - catchClauseWrapper.setBody(bodyWrapper); - } catch (e) { - console.error("CATCHCLAUSE - Could not set body! Reason of the error: " + e + "\n"); - } + globals.safeSet(catchClauseWrapper, "setBody", node.body, "CATCHCLAUSE - Could not set body!"); } if (node.param != null) { - var paramWrapper = globals.getWrapperOfNode(node.param); - try { - catchClauseWrapper.setParam(paramWrapper); - } catch (e) { - console.error("CATCHCLAUSE - Could not set param! Reason of the error: " + e + "\n"); - } + globals.safeSet(catchClauseWrapper, "setParam", node.param, "CATCHCLAUSE - Could not set param!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/statement/continueStatement.js b/javascript/cl/JSAN/src/ast/statement/continueStatement.js index bcb2a20..21f6c48 100644 --- a/javascript/cl/JSAN/src/ast/statement/continueStatement.js +++ b/javascript/cl/JSAN/src/ast/statement/continueStatement.js @@ -18,27 +18,22 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var continueStatement = factory.createContinueStatementWrapper(); + const continueStatement = factory.createContinueStatementWrapper(); globals.setPositionInfo(node, continueStatement); return continueStatement; } else { - var continueStatementWrapper = globals.getWrapperOfNode(node); + const continueStatementWrapper = globals.getWrapperOfNode(node); if (node.label != null) { - var labelWrapper = globals.getWrapperOfNode(node.label); - try { - continueStatementWrapper.setLabel(labelWrapper); - } catch (e) { - console.error("CONTINUESTATEMENT - Could not set label! Reason of the error: " + e + "\n"); - } + globals.safeSet(continueStatementWrapper, "setLabel", node.label, "CONTINUESTATEMENT - Could not set label!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/statement/debuggerStatement.js b/javascript/cl/JSAN/src/ast/statement/debuggerStatement.js index 7d0fdc3..7d24c08 100644 --- a/javascript/cl/JSAN/src/ast/statement/debuggerStatement.js +++ b/javascript/cl/JSAN/src/ast/statement/debuggerStatement.js @@ -18,16 +18,17 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var debuggerStatement = factory.createDebuggerStatementWrapper(); + const debuggerStatement = factory.createDebuggerStatementWrapper(); globals.setPositionInfo(node, debuggerStatement); return debuggerStatement; } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/statement/doWhileStatement.js b/javascript/cl/JSAN/src/ast/statement/doWhileStatement.js index bb7861c..9f48dff 100644 --- a/javascript/cl/JSAN/src/ast/statement/doWhileStatement.js +++ b/javascript/cl/JSAN/src/ast/statement/doWhileStatement.js @@ -18,37 +18,27 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var doWhileStatement = factory.createDoWhileStatementWrapper(); + const doWhileStatement = factory.createDoWhileStatementWrapper(); globals.setPositionInfo(node, doWhileStatement); return doWhileStatement; } else { - var doWhileStatementWrapper = globals.getWrapperOfNode(node); + const doWhileStatementWrapper = globals.getWrapperOfNode(node); if (node.test != null) { - var testWrapper = globals.getWrapperOfNode(node.test); - try { - doWhileStatementWrapper.setTest(testWrapper); - } catch (e) { - console.error("DOWHILESTATEMENT - Could not set test! Reason of the error: " + e + "\n"); - } + globals.safeSet(doWhileStatementWrapper, "setTest", node.test, "CONTINUESTATEMENT - Could not set test!"); } if (node.body != null) { - var bodyWrapper = globals.getWrapperOfNode(node.body); - try { - doWhileStatementWrapper.setBody(bodyWrapper); - } catch (e) { - console.error("DOWHILESTATEMENT - Could not set body! Reason of the error: " + e + "\n"); - } + globals.safeSet(doWhileStatementWrapper, "setBody", node.body, "CONTINUESTATEMENT - Could not set body!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/statement/emptyStatement.js b/javascript/cl/JSAN/src/ast/statement/emptyStatement.js index fedd53e..4c97c19 100644 --- a/javascript/cl/JSAN/src/ast/statement/emptyStatement.js +++ b/javascript/cl/JSAN/src/ast/statement/emptyStatement.js @@ -18,16 +18,17 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var emptyStatements = factory.createEmptyStatementWrapper(); + const emptyStatements = factory.createEmptyStatementWrapper(); globals.setPositionInfo(node, emptyStatements); return emptyStatements; } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/statement/expressionStatement.js b/javascript/cl/JSAN/src/ast/statement/expressionStatement.js index 93c9487..825a4ec 100644 --- a/javascript/cl/JSAN/src/ast/statement/expressionStatement.js +++ b/javascript/cl/JSAN/src/ast/statement/expressionStatement.js @@ -18,27 +18,22 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var expressionStatement = factory.createExpressionStatementWrapper(); + const expressionStatement = factory.createExpressionStatementWrapper(); globals.setPositionInfo(node, expressionStatement); return expressionStatement; } else { - var expressionStatementWrapper = globals.getWrapperOfNode(node); + const expressionStatementWrapper = globals.getWrapperOfNode(node); if (node.expression != null) { - var expressionWrapper = globals.getWrapperOfNode(node.expression); - try { - expressionStatementWrapper.setExpression(expressionWrapper); - } catch (e) { - console.error("EXPRESSIONSTATEMENT - Could not set expression! Reason of the error: " + e + "\n"); - } + globals.safeSet(expressionStatementWrapper, "setExpression", node.expression, "EXPRESSIONSTATEMENT - Could not set expression!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/statement/forInStatement.js b/javascript/cl/JSAN/src/ast/statement/forInStatement.js index 0731d80..27dfa8b 100644 --- a/javascript/cl/JSAN/src/ast/statement/forInStatement.js +++ b/javascript/cl/JSAN/src/ast/statement/forInStatement.js @@ -18,46 +18,31 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var forInStatement = factory.createForInStatementWrapper(); + const forInStatement = factory.createForInStatementWrapper(); globals.setPositionInfo(node, forInStatement); return forInStatement; } else { - var forInStatementWrapper = globals.getWrapperOfNode(node); + const forInStatementWrapper = globals.getWrapperOfNode(node); if (node.left != null) { - var leftWrapper = globals.getWrapperOfNode(node.left); - try { - forInStatementWrapper.setLeft(leftWrapper); - } catch (e) { - console.error("FORINSTATEMENT - Could not set left! Reason of the error: " + e + "\n"); - } + globals.safeSet(forInStatementWrapper, "setLeft", node.left, "FORINSTATEMENT - Could not set left!"); } if (node.right != null) { - var rightWrapper = globals.getWrapperOfNode(node.right); - try { - forInStatementWrapper.setRight(rightWrapper); - } catch (e) { - console.error("FORINSTATEMENT - Could not set right! Reason of the error: " + e + "\n"); - } + globals.safeSet(forInStatementWrapper, "setRight", node.right, "FORINSTATEMENT - Could not set right!"); } if (node.body != null) { - var bodyWrapper = globals.getWrapperOfNode(node.body); - try { - forInStatementWrapper.setBody(bodyWrapper); - } catch (e) { - console.error("FORINSTATEMENT - Could not set body! Reason of the error: " + e + "\n"); - } + globals.safeSet(forInStatementWrapper, "setBody", node.body, "FORINSTATEMENT - Could not set body!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/statement/forOfStatement.js b/javascript/cl/JSAN/src/ast/statement/forOfStatement.js index b44e193..3e4e71f 100644 --- a/javascript/cl/JSAN/src/ast/statement/forOfStatement.js +++ b/javascript/cl/JSAN/src/ast/statement/forOfStatement.js @@ -18,49 +18,32 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var forOfStatement = factory.createForOfStatementWrapper(); - // TODO: uncomment if supported - //forOfStatement.setAwait(node.await); + const forOfStatement = factory.createForOfStatementWrapper(); + forOfStatement.setAwait(node.await); globals.setPositionInfo(node, forOfStatement); return forOfStatement; } else { - var forOfStatementWrapper = globals.getWrapperOfNode(node); + const forOfStatementWrapper = globals.getWrapperOfNode(node); if (node.left != null) { - var leftWrapper = globals.getWrapperOfNode(node.left); - try { - forOfStatementWrapper.setLeft(leftWrapper); - } catch (e) { - console.error("FOROFSTATEMENT - Could not set left! Reason of the error: " + e + "\n"); - } + globals.safeSet(forOfStatementWrapper, "setLeft", node.left, "FOROFSTATEMENT - Could not set left!"); } if (node.right != null) { - var rightWrapper = globals.getWrapperOfNode(node.right); - try { - forOfStatementWrapper.setRight(rightWrapper); - } catch (e) { - console.error("FOROFSTATEMENT - Cannot set right! Reason of the error: " + e + "\n"); - } + globals.safeSet(forOfStatementWrapper, "setRight", node.right, "FOROFSTATEMENT - Could not set right!"); } if (node.body != null) { - var bodyWrapper = globals.getWrapperOfNode(node.body); - try { - forOfStatementWrapper.setBody(bodyWrapper); - } catch (e) { - console.error("FOROFSTATEMENT - Could not set body! Reason of the error: " + e + "\n"); - } + globals.safeSet(forOfStatementWrapper, "setBody", node.body, "FOROFSTATEMENT - Could not set body!"); } - - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/statement/forStatement.js b/javascript/cl/JSAN/src/ast/statement/forStatement.js index b240bff..f53e265 100644 --- a/javascript/cl/JSAN/src/ast/statement/forStatement.js +++ b/javascript/cl/JSAN/src/ast/statement/forStatement.js @@ -18,56 +18,35 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var forStatement = factory.createForStatementWrapper(); + const forStatement = factory.createForStatementWrapper(); globals.setPositionInfo(node, forStatement); return forStatement; } else { - var forStatementWrapper = globals.getWrapperOfNode(node); + const forStatementWrapper = globals.getWrapperOfNode(node); if (node.init != null) { - var initWrapper = globals.getWrapperOfNode(node.init); - try { - forStatementWrapper.setInit(initWrapper); - } catch (e) { - console.error("FORSTATEMENT - Could not set init! Reason of the error: " + e + "\n"); - } + globals.safeSet(forStatementWrapper, "setInit", node.init, "FORSTATEMENT - Could not set init!"); } if (node.test != null) { - var testWrapper = globals.getWrapperOfNode(node.test); - try { - forStatementWrapper.setTest(testWrapper); - } catch (e) { - console.error("FORSTATEMENT - Could not set test! Reason of the error: " + e + "\n"); - } + globals.safeSet(forStatementWrapper, "setTest", node.test, "FORSTATEMENT - Could not set test!"); } if (node.update != null) { - var updateWrapper = globals.getWrapperOfNode(node.update); - try { - forStatementWrapper.setUpdate(updateWrapper); - } catch (e) { - console.error("FORSTATEMENT - Could not set update! Reason of the error: " + e + "\n"); - } + globals.safeSet(forStatementWrapper, "setUpdate", node.update, "FORSTATEMENT - Could not set update!"); } if (node.body != null) { - var bodyWrapper = globals.getWrapperOfNode(node.body); - try { - forStatementWrapper.setBody(bodyWrapper); - } catch (e) { - console.error("FORSTATEMENT - Could not set body! Reason of the error: " + e + "\n"); - } + globals.safeSet(forStatementWrapper, "setBody", node.body, "FORSTATEMENT - Could not set body!"); } - - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/statement/ifStatement.js b/javascript/cl/JSAN/src/ast/statement/ifStatement.js index 3f36710..ff653d4 100644 --- a/javascript/cl/JSAN/src/ast/statement/ifStatement.js +++ b/javascript/cl/JSAN/src/ast/statement/ifStatement.js @@ -18,47 +18,31 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var ifStatement = factory.createIfStatementWrapper(); + const ifStatement = factory.createIfStatementWrapper(); globals.setPositionInfo(node, ifStatement); return ifStatement; } else { - var ifStatementWrapper = globals.getWrapperOfNode(node); - + const ifStatementWrapper = globals.getWrapperOfNode(node); if (node.consequent != null) { - var consequentWrapper = globals.getWrapperOfNode(node.consequent); - try { - ifStatementWrapper.setConsequent(consequentWrapper); - } catch (e) { - console.error("IFSTATEMENT - Could not set consequent! Reason of the error: " + e + "\n"); - } + globals.safeSet(ifStatementWrapper, "setConsequent", node.consequent, "IFSTATEMENT - Could not set consequent!"); } if (node.test != null) { - var testWrapper = globals.getWrapperOfNode(node.test); - try { - ifStatementWrapper.setTest(testWrapper); - } catch (e) { - console.error("IFSTATEMENT - Could not set test! Reason of the error: " + e + "\n"); - } + globals.safeSet(ifStatementWrapper, "setTest", node.test, "IFSTATEMENT - Could not set test!"); } if (node.alternate != null) { - var alternateWrapper = globals.getWrapperOfNode(node.alternate); - try { - ifStatementWrapper.setAlternate(alternateWrapper); - } catch (e) { - console.error("IFSTATEMENT - Could not set alternate! Reason of the error: " + e + "\n"); - } + globals.safeSet(ifStatementWrapper, "setAlternate", node.alternate, "IFSTATEMENT - Could not set alternate!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/statement/labeledStatement.js b/javascript/cl/JSAN/src/ast/statement/labeledStatement.js index 78d4ad5..db6c87d 100644 --- a/javascript/cl/JSAN/src/ast/statement/labeledStatement.js +++ b/javascript/cl/JSAN/src/ast/statement/labeledStatement.js @@ -18,38 +18,27 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var labeledStatement = factory.createLabeledStatementWrapper(); + const labeledStatement = factory.createLabeledStatementWrapper(); globals.setPositionInfo(node, labeledStatement); return labeledStatement; } else { - var labeledStatementWrapper = globals.getWrapperOfNode(node); - + const labeledStatementWrapper = globals.getWrapperOfNode(node); if (node.label != null) { - var labelWrapper = globals.getWrapperOfNode(node.label); - try { - labeledStatementWrapper.setLabel(labelWrapper); - } catch (e) { - console.error("LABELEDSTATEMENT - Could not set label! Reason of the error: " + e + "\n"); - } + globals.safeSet(labeledStatementWrapper, "setLabel", node.label, "LABELEDSTATEMENT - Could not set label!"); } if (node.body != null) { - var bodyWrapper = globals.getWrapperOfNode(node.body); - try { - labeledStatementWrapper.setBody(bodyWrapper); - } catch (e) { - console.error("LABELEDSTATEMENT - Could not set body! Reason of the error: " + e + "\n"); - } + globals.safeSet(labeledStatementWrapper, "setBody", node.body, "LABELEDSTATEMENT - Could not set body!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/statement/objectPattern.js b/javascript/cl/JSAN/src/ast/statement/objectPattern.js index 420d331..75e8124 100644 --- a/javascript/cl/JSAN/src/ast/statement/objectPattern.js +++ b/javascript/cl/JSAN/src/ast/statement/objectPattern.js @@ -18,30 +18,26 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var objectPattern = factory.createObjectPatternWrapper(); + const objectPattern = factory.createObjectPatternWrapper(); globals.setPositionInfo(node, objectPattern); return objectPattern; } else { - var objectPatternWrapper = globals.getWrapperOfNode(node); + const objectPatternWrapper = globals.getWrapperOfNode(node); if (node.properties != null) { - for (var i = 0; i < node.properties.length; i++) { + for (let i = 0; i < node.properties.length; i++) { if (node.properties[i] != null) { - var propertiesWrapper = globals.getWrapperOfNode(node.properties[i]); - try { - objectPatternWrapper.addProperties(propertiesWrapper); - } catch (e) { - console.error("OBJECTPATTERN - Could not add property! Reason of the error: " + e + "\n"); - } + globals.safeSet(objectPatternWrapper, "addProperties", node.properties[i], "OBJECTPATTERN - Could not add property!"); } } } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/statement/restElement.js b/javascript/cl/JSAN/src/ast/statement/restElement.js index 20539e8..f82ab46 100644 --- a/javascript/cl/JSAN/src/ast/statement/restElement.js +++ b/javascript/cl/JSAN/src/ast/statement/restElement.js @@ -18,28 +18,23 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var restElement = factory.createRestElementWrapper(); + const restElement = factory.createRestElementWrapper(); globals.setPositionInfo(node, restElement); return restElement; } else { - var restElementWrapper = globals.getWrapperOfNode(node); + const restElementWrapper = globals.getWrapperOfNode(node); if (node.argument != null) { - var argumentWrapper = globals.getWrapperOfNode(node.argument); - try { - restElementWrapper.setArgument(argumentWrapper); - } catch (e) { - console.error("RESTELEMENT - Could not set argument! Reason of the error: " + e + "\n"); - } + globals.safeSet(restElementWrapper, "setArgument", node.argument, "RESTELEMENT - Could not set argument!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/statement/returnStatement.js b/javascript/cl/JSAN/src/ast/statement/returnStatement.js index 69083ab..298a001 100644 --- a/javascript/cl/JSAN/src/ast/statement/returnStatement.js +++ b/javascript/cl/JSAN/src/ast/statement/returnStatement.js @@ -18,29 +18,24 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var returnStatement = factory.createReturnStatementWrapper(); + const returnStatement = factory.createReturnStatementWrapper(); globals.setPositionInfo(node, returnStatement); return returnStatement; } else { - var returnStatementWrapper = globals.getWrapperOfNode(node); + const returnStatementWrapper = globals.getWrapperOfNode(node); if (node.argument != null) { - var argumentWrapper = globals.getWrapperOfNode(node.argument); - try { - returnStatementWrapper.setArgument(argumentWrapper); - } catch (e) { - console.error("RETURNSTATEMENT - Could not set argument! Reason of the error: " + e + "\n"); - } + globals.safeSet(returnStatementWrapper, "setArgument", node.argument, "RETURNSTATEMENT - Could not set argument!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/statement/switchCase.js b/javascript/cl/JSAN/src/ast/statement/switchCase.js index 09e74ad..5ba496a 100644 --- a/javascript/cl/JSAN/src/ast/statement/switchCase.js +++ b/javascript/cl/JSAN/src/ast/statement/switchCase.js @@ -18,40 +18,29 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var switchCase = factory.createSwitchCaseWrapper(); + const switchCase = factory.createSwitchCaseWrapper(); globals.setPositionInfo(node, switchCase); return switchCase; } else { - var switchCaseWrapper = globals.getWrapperOfNode(node); - + const switchCaseWrapper = globals.getWrapperOfNode(node); if (node.test != null) { - var testWrapper = globals.getWrapperOfNode(node.test); - try { - switchCaseWrapper.setTest(testWrapper); - } catch (e) { - console.error("SWITCHCASE - Could not set test! Reason of the error: " + e + "\n"); - } + globals.safeSet(switchCaseWrapper, "setTest", node.test, "SWITCHCASE - Could not set test!"); } - if (node.consequent != null) { - for (var i = 0; i < node.consequent.length; i++) { + for (let i = 0; i < node.consequent.length; i++) { if (node.consequent[i] != null) { - var consequentWrapper = globals.getWrapperOfNode(node.consequent[i]); - try { - switchCaseWrapper.addConsequent(consequentWrapper); - } catch (e) { - console.error("SWITCHCASE - Could not add consequent! Reason of the error: " + e + "\n"); - } + globals.safeSet(switchCaseWrapper, "addConsequent", node.consequent[i], "SWITCHCASE - Could not add consequent!"); } } } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/statement/switchStatement.js b/javascript/cl/JSAN/src/ast/statement/switchStatement.js index d47ff7c..5fc4b78 100644 --- a/javascript/cl/JSAN/src/ast/statement/switchStatement.js +++ b/javascript/cl/JSAN/src/ast/statement/switchStatement.js @@ -18,40 +18,30 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var switchStatement = factory.createSwitchStatementWrapper(); + const switchStatement = factory.createSwitchStatementWrapper(); globals.setPositionInfo(node, switchStatement); return switchStatement; } else { - var switchStatementWrapper = globals.getWrapperOfNode(node); + const switchStatementWrapper = globals.getWrapperOfNode(node); if (node.cases != null) { - for (var i = 0; i < node.cases.length; i++) { + for (let i = 0; i < node.cases.length; i++) { if (node.cases[i] != null) { - var casesWrapper = globals.getWrapperOfNode(node.cases[i]); - try { - switchStatementWrapper.addCases(casesWrapper); - } catch (e) { - console.error("SWITCHSTATEMENT - Could not add case! Reason of the error: " + e + "\n"); - } + globals.safeSet(switchStatementWrapper, "addCases", node.cases[i], "SWITCHSTATEMENT - Could not add case!"); } } } + if (node.discriminant != null) { - var discriminantWrapper = globals.getWrapperOfNode(node.discriminant); - try { - switchStatementWrapper.setDiscriminant(discriminantWrapper); - } catch (e) { - console.error("SWITCHSTATEMENT - Could not set discriminant! Reason of the error: " + e + "\n"); - } + globals.safeSet(switchStatementWrapper, "setDiscriminant", node.discriminant, "SWITCHSTATEMENT - Could not set discriminant!"); } - - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/statement/throwStatement.js b/javascript/cl/JSAN/src/ast/statement/throwStatement.js index a9a79bc..1292cc9 100644 --- a/javascript/cl/JSAN/src/ast/statement/throwStatement.js +++ b/javascript/cl/JSAN/src/ast/statement/throwStatement.js @@ -18,29 +18,24 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var throwStatement = factory.createThrowStatementWrapper(); + const throwStatement = factory.createThrowStatementWrapper(); globals.setPositionInfo(node, throwStatement); return throwStatement; } else { - var throwStatementWrapper = globals.getWrapperOfNode(node); + const throwStatementWrapper = globals.getWrapperOfNode(node); if (node.argument != null) { - var argumentWrapper = globals.getWrapperOfNode(node.argument); - try { - throwStatementWrapper.setArgument(argumentWrapper); - } catch (e) { - console.error("THROWSTATEMENT - Could not set argument! Reason of the error: " + e + "\n"); - } + globals.safeSet(throwStatementWrapper, "setArgument", node.argument, "THROWSTATEMENT - Could not set argument!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/statement/tryStatement.js b/javascript/cl/JSAN/src/ast/statement/tryStatement.js index 8db2c66..fb64248 100644 --- a/javascript/cl/JSAN/src/ast/statement/tryStatement.js +++ b/javascript/cl/JSAN/src/ast/statement/tryStatement.js @@ -18,46 +18,31 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var tryStatement = factory.createTryStatementWrapper(); + const tryStatement = factory.createTryStatementWrapper(); globals.setPositionInfo(node, tryStatement); return tryStatement; } else { - var tryStatementWrapper = globals.getWrapperOfNode(node); + const tryStatementWrapper = globals.getWrapperOfNode(node); if (node.handler != null) { - var handlerWrapper = globals.getWrapperOfNode(node.handler); - try { - tryStatementWrapper.setHandler(handlerWrapper); - } catch (e) { - console.error("TRYSTATEMENT - Could not set handler! Reason of the error: " + e + "\n"); - } + globals.safeSet(tryStatementWrapper, "setHandler", node.handler, "TRYSTATEMENT - Could not set handler!"); } if (node.block != null) { - var blockWrapper = globals.getWrapperOfNode(node.block); - try { - tryStatementWrapper.setBlock(blockWrapper); - } catch (e) { - console.error("TRYSTATEMENT - Could not set block! Reason of the error: " + e + "\n"); - } + globals.safeSet(tryStatementWrapper, "setBlock", node.block, "TRYSTATEMENT - Could not set block!"); } if (node.finalizer != null) { - var finalizerWrapper = globals.getWrapperOfNode(node.finalizer); - try { - tryStatementWrapper.setFinalizer(finalizerWrapper); - } catch (e) { - console.error("TRYSTATEMENT - Could not set finalizer! Reason of the error: " + e + "\n"); - } + globals.safeSet(tryStatementWrapper, "setFinalizer", node.finalizer, "TRYSTATEMENT - Could not set finalizer!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/statement/whileStatement.js b/javascript/cl/JSAN/src/ast/statement/whileStatement.js index a4dc88d..e684d5b 100644 --- a/javascript/cl/JSAN/src/ast/statement/whileStatement.js +++ b/javascript/cl/JSAN/src/ast/statement/whileStatement.js @@ -18,37 +18,27 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var whileStatement = factory.createWhileStatementWrapper(); + const whileStatement = factory.createWhileStatementWrapper(); globals.setPositionInfo(node, whileStatement); return whileStatement; } else { - var whileStatementWrapper = globals.getWrapperOfNode(node); + const whileStatementWrapper = globals.getWrapperOfNode(node); if (node.test != null) { - var testWrapper = globals.getWrapperOfNode(node.test); - try { - whileStatementWrapper.setTest(testWrapper); - } catch (e) { - console.error("WHILESTATEMENT - Could not set test! Reason of the error: " + e + "\n"); - } + globals.safeSet(whileStatementWrapper, "setTest", node.test, "WHILESTATEMENT - Could not set test!"); } if (node.body != null) { - var bodyWrapper = globals.getWrapperOfNode(node.body); - try { - whileStatementWrapper.setBody(bodyWrapper); - } catch (e) { - console.error("WHILESTATEMENT - Could not set body! Reason of the error: " + e + "\n"); - } + globals.safeSet(whileStatementWrapper, "setBody", node.body, "WHILESTATEMENT - Could not set body!"); } - } } diff --git a/javascript/cl/JSAN/src/ast/statement/withStatement.js b/javascript/cl/JSAN/src/ast/statement/withStatement.js index ea2278a..8ff1637 100644 --- a/javascript/cl/JSAN/src/ast/statement/withStatement.js +++ b/javascript/cl/JSAN/src/ast/statement/withStatement.js @@ -18,37 +18,28 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var withStatement = factory.createWithStatementWrapper(); + const withStatement = factory.createWithStatementWrapper(); globals.setPositionInfo(node, withStatement); return withStatement; } else { - var withStatementWrapper = globals.getWrapperOfNode(node); + const withStatementWrapper = globals.getWrapperOfNode(node); if (node.object != null) { - var objectWrapper = globals.getWrapperOfNode(node.object); - try { - withStatementWrapper.setObject(objectWrapper); - } catch (e) { - console.error("WITHSTATEMENT - Could not set object! Reason of the error: " + e + "\n"); - } + globals.safeSet(withStatementWrapper, "setObject", node.object, "WITHSTATEMENT - Could not set object!"); } if (node.body != null) { - var bodyWrapper = globals.getWrapperOfNode(node.body); - try { - withStatementWrapper.setBody(bodyWrapper); - } catch (e) { - console.error("WITHSTATEMENT - Could not set body! Reason of the error: " + e + "\n"); - } + globals.safeSet(withStatementWrapper, "setBody", node.body, "WITHSTATEMENT - Could not set body!"); } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/structure/class.js b/javascript/cl/JSAN/src/ast/structure/class.js index f9f004a..6494296 100644 --- a/javascript/cl/JSAN/src/ast/structure/class.js +++ b/javascript/cl/JSAN/src/ast/structure/class.js @@ -18,46 +18,31 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var classNode = factory.createClassWrapper(); + const classNode = factory.createClassWrapper(); globals.setPositionInfo(node, classNode); return classNode; } else { - var classWrapper = globals.getWrapperOfNode(node); + const classWrapper = globals.getWrapperOfNode(node); if (node.superClass != null) { - var superClassWrapper = globals.getWrapperOfNode(node.superClass); - try { - classWrapper.setSuperClass(superClassWrapper); - } catch (e) { - console.error("CLASS - Could not set superclass! Reason of the error: " + e + "\n"); - } + globals.safeSet(classWrapper, "setSuperClass", node.superClass, "CLASS - Could not set superclass!"); } if (node.body != null) { - var bodyWrapper = globals.getWrapperOfNode(node.body); - try { - classWrapper.setBody(bodyWrapper); - } catch (e) { - console.error("CLASS - Could not set body! Reason of the error: " + e + "\n"); - } + globals.safeSet(classWrapper, "setBody", node.body, "CLASS - Could not set body!"); } if (node.id != null) { - var identifierWrapper = globals.getWrapperOfNode(node.id); - try { - classWrapper.setIdentifier(identifierWrapper); - } catch (e) { - console.error("CLASS - Could not set identifier! Reason of the error: " + e + "\n"); - } + globals.safeSet(classWrapper, "setIdentifier", node.id, "CLASS - Could not set identifier!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/structure/classBody.js b/javascript/cl/JSAN/src/ast/structure/classBody.js index 2faf523..dd6c60b 100644 --- a/javascript/cl/JSAN/src/ast/structure/classBody.js +++ b/javascript/cl/JSAN/src/ast/structure/classBody.js @@ -18,30 +18,26 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var classBody = factory.createClassBodyWrapper(); + const classBody = factory.createClassBodyWrapper(); globals.setPositionInfo(node, classBody); return classBody; } else { - var classBodyWrapper = globals.getWrapperOfNode(node); + const classBodyWrapper = globals.getWrapperOfNode(node); if (node.body != null) { - for (var i = 0; i < node.body.length; i++) { + for (let i = 0; i < node.body.length; i++) { if (node.body[i] != null) { - var bodyWrapper = globals.getWrapperOfNode(node.body[i]); - try { - classBodyWrapper.addBody(bodyWrapper); - } catch (e) { - console.error("CLASSBODY - Could not add body! Reason of the error: " + e + "\n"); - } + globals.safeSet(classBodyWrapper, "addBody", node.body[i], "CLASSBODY - Could not add body!"); } } } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/structure/exportSpecifier.js b/javascript/cl/JSAN/src/ast/structure/exportSpecifier.js index 531a137..9d1c60f 100644 --- a/javascript/cl/JSAN/src/ast/structure/exportSpecifier.js +++ b/javascript/cl/JSAN/src/ast/structure/exportSpecifier.js @@ -18,37 +18,28 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var exportSpecifier = factory.createExportSpecifierWrapper(); + const exportSpecifier = factory.createExportSpecifierWrapper(); globals.setPositionInfo(node, exportSpecifier); return exportSpecifier; } else { - var exportSpecifierWrapper = globals.getWrapperOfNode(node); + const exportSpecifierWrapper = globals.getWrapperOfNode(node); if (node.exported != null) { - var exportedWrapper = globals.getWrapperOfNode(node.exported); - try { - exportSpecifierWrapper.setExported(exportedWrapper); - } catch (e) { - console.error("EXPORTSPECIFIER - Could not set exported! Reason of the error: " + e + "\n"); - } + globals.safeSet(exportSpecifierWrapper, "setExported", node.exported, "EXPORTSPECIFIER - Could not set exported!"); } if (node.local != null) { - var localWrapper = globals.getWrapperOfNode(node.local); - try { - exportSpecifierWrapper.setLocal(localWrapper); - } catch (e) { - console.error("EXPORTSPECIFIER - Could not set local! Reason of the error: " + e + "\n"); - } + globals.safeSet(exportSpecifierWrapper, "setLocal", node.local, "EXPORTSPECIFIER - Could not set local!"); } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/structure/importDefaultSpecifier.js b/javascript/cl/JSAN/src/ast/structure/importDefaultSpecifier.js index e7452e4..c0add03 100644 --- a/javascript/cl/JSAN/src/ast/structure/importDefaultSpecifier.js +++ b/javascript/cl/JSAN/src/ast/structure/importDefaultSpecifier.js @@ -18,28 +18,23 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var importDefaultSpecifier = factory.createImportDefaultSpecifierWrapper(); + const importDefaultSpecifier = factory.createImportDefaultSpecifierWrapper(); globals.setPositionInfo(node, importDefaultSpecifier); return importDefaultSpecifier; } else { - var importDefaultSpecifierWrapper = globals.getWrapperOfNode(node); + const importDefaultSpecifierWrapper = globals.getWrapperOfNode(node); if (node.local != null) { - var localWrapper = globals.getWrapperOfNode(node.local); - try { - importDefaultSpecifierWrapper.setLocal(localWrapper); - } catch (e) { - console.error("IMPORTDEFAULTSPECIFIER - Could not set local! Reason of the error: " + e + "\n"); - } + globals.safeSet(importDefaultSpecifierWrapper, "setLocal", node.local, "IMPORTDEFAULTSPECIFIER - Could not set local!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/structure/importNamespaceSpecifier.js b/javascript/cl/JSAN/src/ast/structure/importNamespaceSpecifier.js index 73f3a2a..6400169 100644 --- a/javascript/cl/JSAN/src/ast/structure/importNamespaceSpecifier.js +++ b/javascript/cl/JSAN/src/ast/structure/importNamespaceSpecifier.js @@ -18,28 +18,23 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var importNamespaceSpecifier = factory.createImportNamespaceSpecifierWrapper(); + const importNamespaceSpecifier = factory.createImportNamespaceSpecifierWrapper(); globals.setPositionInfo(node, importNamespaceSpecifier); return importNamespaceSpecifier; } else { - var importNamespaceSpecifierWrapper = globals.getWrapperOfNode(node); + const importNamespaceSpecifierWrapper = globals.getWrapperOfNode(node); if (node.local != null) { - var localWrapper = globals.getWrapperOfNode(node.local); - try { - importNamespaceSpecifierWrapper.setLocal(localWrapper); - } catch (e) { - console.error("IMPORTNAMESPACESPECIFIER - Could not set local! Reason of the error: " + e + "\n"); - } + globals.safeSet(importNamespaceSpecifierWrapper, "setLocal", node.local, "IMPORTNAMESPACESPECIFIER - Could not set local!"); } - } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/structure/importSpecifier.js b/javascript/cl/JSAN/src/ast/structure/importSpecifier.js index c3ac8ca..7ca8b37 100644 --- a/javascript/cl/JSAN/src/ast/structure/importSpecifier.js +++ b/javascript/cl/JSAN/src/ast/structure/importSpecifier.js @@ -18,37 +18,28 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); +import * as globals from '../../globals.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var importSpecifier = factory.createImportSpecifierWrapper(); + const importSpecifier = factory.createImportSpecifierWrapper(); globals.setPositionInfo(node, importSpecifier); return importSpecifier; } else { - var importSpecifierWrapper = globals.getWrapperOfNode(node); + const importSpecifierWrapper = globals.getWrapperOfNode(node); if (node.imported != null) { - var importedWrapper = globals.getWrapperOfNode(node.imported); - try { - importSpecifierWrapper.setImported(importedWrapper); - } catch (e) { - console.error("IMPORTSPECIFIER - Could not set imported! Reason of the error: " + e + "\n"); - } + globals.safeSet(importSpecifierWrapper, "setImported", node.imported, "IMPORTSPECIFIER - Could not set imported!"); } if (node.local != null) { - var localWrapper = globals.getWrapperOfNode(node.local); - try { - importSpecifierWrapper.setLocal(localWrapper); - } catch (e) { - console.error("IMPORTSPECIFIER - Could not set local! Reason of the error: " + e + "\n"); - } + globals.safeSet(importSpecifierWrapper, "setLocal", node.local, "IMPORTSPECIFIER - Could not set local!"); } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/structure/methodDefinition.js b/javascript/cl/JSAN/src/ast/structure/methodDefinition.js index d7f8a7d..8c9be97 100644 --- a/javascript/cl/JSAN/src/ast/structure/methodDefinition.js +++ b/javascript/cl/JSAN/src/ast/structure/methodDefinition.js @@ -18,41 +18,32 @@ * limitations under the Licence. */ -var globals = require('../../globals'); -var factory = globals.getFactory(); -const conversions = require('../conversions'); +import * as globals from '../../globals.js'; +import * as conversions from '../conversions.js'; -module.exports = function (node, parent, firstVisit) { +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { if (firstVisit) { if (globals.getWrapperOfNode(node) !== undefined) { return; } - var methodDefinition = factory.createMethodDefinitionWrapper(); + const methodDefinition = factory.createMethodDefinitionWrapper(); globals.setPositionInfo(node, methodDefinition); methodDefinition.setKind(conversions.convertMethodDefinitionKind(node.kind)); methodDefinition.setComputed(node.computed); methodDefinition.setStatic(node.static); return methodDefinition; } else { - var methodDefinitionWrapper = globals.getWrapperOfNode(node); + const methodDefinitionWrapper = globals.getWrapperOfNode(node); if (node.key != null) { - var keyWrapper = globals.getWrapperOfNode(node.key); - try { - methodDefinitionWrapper.setKey(keyWrapper); - } catch (e) { - console.error("METHODDEFINITION - Could not set key! Reason of the error: " + e + "\n"); - } + globals.safeSet(methodDefinitionWrapper, "setKey", node.key, "METHODDEFINITION - Could not set key!"); } if (node.value != null) { - var valueWrapper = globals.getWrapperOfNode(node.value); - try { - methodDefinitionWrapper.setValue(valueWrapper); - } catch (e) { - console.error("METHODDEFINITION - Could not set value! Reason of the error: " + e + "\n"); - } + globals.safeSet(methodDefinitionWrapper, "setValue", node.value, "METHODDEFINITION - Could not set value!"); } } -} \ No newline at end of file +} diff --git a/javascript/cl/JSAN/src/ast/structure/propertyDefinition.js b/javascript/cl/JSAN/src/ast/structure/propertyDefinition.js new file mode 100644 index 0000000..40eb637 --- /dev/null +++ b/javascript/cl/JSAN/src/ast/structure/propertyDefinition.js @@ -0,0 +1,28 @@ +import * as globals from '../../globals.js'; + +const factory = globals.getFactory(); + +export default function (node, parent, firstVisit) { + if (firstVisit) { + if (globals.getWrapperOfNode(node) !== undefined) { + return; + } + const propertyDefinition = factory.createPropertyDefinitionWrapper(); + globals.setPositionInfo(node, propertyDefinition); + + propertyDefinition.setComputed(node.computed); + propertyDefinition.setStatic(node.static); + return propertyDefinition; + } else { + const propertyDefinitionWrapper = globals.getWrapperOfNode(node); + + if (node.key !== null) { + globals.safeSet(propertyDefinitionWrapper, "setKey", node.key, "PROPERTYDEFINITION - Could not set key!"); + } + + if (node.value !== null) { + globals.safeSet(propertyDefinitionWrapper, "setValue", node.value, "PROPERTYDEFINITION - Could not set value!"); + } + + } +} diff --git a/javascript/cl/JSAN/src/globals.js b/javascript/cl/JSAN/src/globals.js index b0cf3b6..cc8c733 100644 --- a/javascript/cl/JSAN/src/globals.js +++ b/javascript/cl/JSAN/src/globals.js @@ -18,88 +18,83 @@ * limitations under the Licence. */ -const hashmap = require('hashmap'); -const addon = require('../javascriptAddon'); -const path = require('path'); - - -var nodeAndWrapperMap = new hashmap(); -var actualFile = undefined; -var factory = new addon.Factory(); -var options = undefined; -var actualProgramNode = null; -var commentMap = new hashmap(); - -module.exports.addComment = function(comment){ - commentMap.set(comment.loc, comment); -}; - -module.exports.isCommentExists = function(comment){ - return commentMap.has(comment.loc); -}; +import {default as hashmap} from 'hashmap'; +import * as path from 'path'; +import * as addon from '../javascriptAddon.node'; + +let nodeAndWrapperMap = new hashmap(); +let actualFile = undefined; +let factory = new addon.Factory(); +let options = undefined; +let actualProgramNode = null; + +/** + * Supported extensions by JSAN + * @type {string[]} + */ +const supportedExts = [ + ".js", + ".ts", + ".html", +] -module.exports.clearCommentMap = function(){ - commentMap.clear(); -}; -module.exports.getActualProgramNode = function () { +let getActualProgramNode = function () { return actualProgramNode; }; -module.exports.setActualProgramNode = function (node) { +let setActualProgramNode = function (node) { actualProgramNode = node; }; -module.exports.setActualFile = function (filename) { +let setActualFile = function (filename) { actualFile = filename; }; -module.exports.getActualFile = function () { +let getActualFile = function () { return actualFile; }; -module.exports.getFactory = function () { +let getFactory = function () { return factory; }; -module.exports.putNodeWrapperPair = function (node, wrapper) { +let putNodeWrapperPair = function (node, wrapper) { nodeAndWrapperMap.set(node, wrapper); }; -module.exports.getWrapperOfNode = function (node) { - return nodeAndWrapperMap.get(node);//returns the wrapper +let getWrapperOfNode = function (node) { + return nodeAndWrapperMap.get(node); //returns the wrapper }; -module.exports.setOptions = function (opt) { +let setOptions = function (opt) { options = opt; }; -module.exports.getOptions = function () { +let getOptions = function () { return options; }; -module.exports.getOption = function (obj) { +let getOption = function (obj) { if (options !== undefined) - if (obj in options) + if (obj in options) { return options[obj]; + } return false; }; - -module.exports.setPositionInfo = function (node, wrapper) { +let setPositionInfo = function (node, wrapper) { try { if (options.useRelativePath) { wrapper.setPath(path.relative(process.cwd(), actualFile)); - } - else { + } else { wrapper.setPath(actualFile); } //A JS file always starts from 1,1 (line, column) if (node.type === "Program") { - wrapper.setPosition(1,0, node.loc.end.line, node.loc.end.column, 1, 0, node.loc.end.line, node.loc.end.column); - } - else { + wrapper.setPosition(1, 0, node.loc.end.line, node.loc.end.column, 1, 0, node.loc.end.line, node.loc.end.column); + } else { wrapper.setPosition( node.loc.start.line, node.loc.start.column, @@ -117,10 +112,9 @@ module.exports.setPositionInfo = function (node, wrapper) { } }; - -module.exports.getLiteralType = function (node) { +let getLiteralType = function (node) { if (typeof (node.value) !== "object") { - var type = typeof (node.value); + const type = typeof (node.value); return type.charAt(0).toLocaleUpperCase() + type.substring(1, type.length); } else { if (node.raw === "null") { @@ -131,3 +125,44 @@ module.exports.getLiteralType = function (node) { } }; + +const safeSet = function (setFunctionContext, functionName, nodeToWrap, errorMessage) { + const wrappedNode = getWrapperOfNode(nodeToWrap); + if (wrappedNode !== undefined) { + try { + // setFunction(wrappedNode); + setFunctionContext[functionName](wrappedNode); + } catch (e) { + console.error(`${errorMessage}. Reason of the error: ${e}\n`); + } + } +} +// +// const safeSet = function (setFunction, nodeToWrap, errorMessage) { +// const wrappedNode = getWrapperOfNode(nodeToWrap); +// if (wrappedNode !== undefined) { +// try { +// setFunction(wrappedNode); +// } catch (e) { +// console.error(`${errorMessage}. Reason of the error: ${e}\n`); +// } +// } +// } + + +export { + getActualProgramNode, + setActualProgramNode, + setActualFile, + getActualFile, + getFactory, + putNodeWrapperPair, + getWrapperOfNode, + setOptions, + getOptions, + getOption, + setPositionInfo, + getLiteralType, + safeSet, + supportedExts +} diff --git a/javascript/cl/JSAN/JSAN.js b/javascript/cl/JSAN/src/index.js similarity index 74% rename from javascript/cl/JSAN/JSAN.js rename to javascript/cl/JSAN/src/index.js index 35eef1f..60070c7 100644 --- a/javascript/cl/JSAN/JSAN.js +++ b/javascript/cl/JSAN/src/index.js @@ -18,18 +18,21 @@ * limitations under the Licence. */ -const clOptions = require('./src/assets/options'); -const htmlExtractor = require('./src/assets/htmlExtractor'); -const astTransformer = require('./src/ast/astTransformer'); -const fs = require('fs'); -const espree = require('espree'); -const path = require('path'); -const JSONStream = require('JSONStream'); -const jcg = require('@persper/js-callgraph/src/runner'); +import * as clOptions from './assets/options.js'; +import * as tsEstree from '@typescript-eslint/typescript-estree'; +import * as globals from './globals.js'; +import * as htmlExtractor from './assets/htmlExtractor.js'; +import {attachComments} from "estree-util-attach-comments"; -let globals = require('./src/globals'); +import * as fs from 'fs'; +import * as path from 'path'; +import * as astTransformer from './ast/astTransformer.js'; +import {trimHashbang} from "./util/util.js"; -const NODEJS_MINIMUM_VERSION = 8; +// const jcg = require('jscg'); +import * as jcg from 'jscg'; + +const NODEJS_MINIMUM_VERSION = 12; globals.setOptions(clOptions.parse()); @@ -64,20 +67,21 @@ Memory.init(); let parsingOptions; let parseCode = function (filePath, code, type) { const options = { + filePath: filePath, sourceType: type, comment: true, - tolerant: true, loc: true, - raw: true, - tokens: true, + tokens: false, range: true, - ecmaVersion: 2018, - attachComment: true, + //ecmaVersion: 2020, }; try { - let rawAst = espree.parse(code, options); + let rawAst = tsEstree.parse(code, options); console.log("Succesfully parsed as " + type + ": " + filePath.absolute); + rawAst = attachComments(rawAst, rawAst.comments); + //fs.writeFileSync('ast.json', JSON.stringify(rawAst, null, 4)); + return {success: true, ast: rawAst, options: options, sourceType: type}; } catch (e) { if (type !== 'script') { @@ -133,26 +137,6 @@ let makeAnalyzeCodeResult = function (filePath, code) { } }; -/** - * Trim shebang to avoid parse error - * Doing it this way will preserve the original absolute positions - * This snippet is taken from: https://github.com/jquery/esprima/issues/1151#issuecomment-85706244 - * @param code the loaded code that might include starting shebang - * @returns the stripped source code - */ -function trimHashbang(code) { - if (code.substring(0, 2) === '#!') { - let end = code.indexOf('\n'); - let filler = ''; - for (let i = 0; i < end; ++i) { - filler += ' '; - } - code = filler + code.substring(end, code.length); - console.log("Leading shebang was removed"); - } - return code; -} - /** * The loadCode method traverse the files, which * we gave in parameter and on each file start the @@ -167,17 +151,13 @@ function loadCode(files) { Memory.check(); let successfullyParsedFiles = []; files.forEach(function (file) { - let filePath = { - absolute: null, - relative: null - }; + let filePath; if (path.isAbsolute(file)) { filePath = { absolute: path.normalize(file), relative: path.relative(process.cwd(), file) }; - } - else { + } else { filePath = { absolute: path.join(process.cwd(), file), relative: path.normalize(file) @@ -193,7 +173,10 @@ function loadCode(files) { return; } - if (path.extname(filePath.relative) === '.js') { + if (globals.supportedExts.includes(path.extname(filePath.relative)) && path.extname(filePath.relative) !== ".html") { + if (path.extname(filePath.relative) === '.ts') { + console.log("TypeScript parsing is currently in experimental phase.") + } try { code = fs.readFileSync(filePath.absolute); code = String(code); @@ -231,24 +214,9 @@ function loadCode(files) { /** * This method save the result into AST file. * @param target The target file of result - * @param result The analyzed, processed result, what we want save into file */ -function saveToAST(target, result) { +function saveToAST(target) { "use strict"; - /* TODO: remove this code once JSAN and ESLintRunner is merged - if (globals.getOption('saveEspreeAst')) { - let transformStream = JSONStream.stringify(); - let outputStream = fs.createWriteStream(target + '.ast'); - transformStream.pipe(outputStream); - result.forEach(transformStream.write); - transformStream.end(); - Memory.check(); - - outputStream.on('finish', function handleFinish() { - console.log('Saving AST to file is done'); - }); - } - */ astTransformer.saveAST(target, globals.getOption('dumpjsml')); } @@ -264,39 +232,56 @@ function analysis() { let resultOfAnalyze = loadCode(globals.getOption('inputList')); let successfullyParsedFiles = resultOfAnalyze.successfullyParsedFiles; Memory.check(); - if (successfullyParsedFiles.length === 0){ - console.log("CrossReference binding is being skipped as there are no modules in the input."); + if (successfullyParsedFiles.length === 0) { + console.log("CrossReference binding is being skipped as there are no modules in the input."); } else { + let resultOfACG = undefined; try { + console.time("ACG"); //jcg.setFiles(globals.getOption('inputList')); jcg.setFiles(successfullyParsedFiles); jcg.setArgs({ - fg: null, + fg: undefined, cg: [], - time: null, + time: undefined, strategy: 'ONESHOT', - countCB: null, - reqJs: null, - output: null, - filter: null + countCB: undefined, + reqJs: undefined, + output: undefined, + filter: undefined }); jcg.setConsoleOutput(false); - let resultOfACG = jcg.build(); + resultOfACG = jcg.build(); + console.timeEnd("ACG"); Memory.check(); + } catch (err) { + console.log("Something bad happened while running JSCG"); + console.log(err) + } + try { + // Transform raw results astTransformer.transform(resultOfAnalyze.result, parsingOptions); Memory.check(); + + // Variable usage let resultOfVU = astTransformer.variableUsages(resultOfAnalyze.result); Memory.check(); - astTransformer.binder("ACG", resultOfAnalyze.result, resultOfACG, "addCalls"); astTransformer.binder("VU", resultOfAnalyze.result, resultOfVU, "setRefersTo"); Memory.check(); + + // Bind cross references + if (resultOfACG !== undefined) { + astTransformer.binder("ACG", resultOfAnalyze.result, resultOfACG, "addCalls"); + Memory.check(); + } else { + console.log("Binding JSCG was skipped due to a previous error.") + } } catch (e) { console.warn(e); - console.warn("CrossReference Binding was failed."); } } - saveToAST(globals.getOption('out'), resultOfAnalyze.result); + saveToAST(globals.getOption('out')); Memory.check(); } @@ -333,10 +318,12 @@ function wrappedAnalysis() { */ function analyzeMain() { "use strict"; - if (process.version.split(".")[0].substring(1) < NODEJS_MINIMUM_VERSION) { // check Node.js version + + const currentNodeVersion = process.version.split(".")[0].substring(1); + if (currentNodeVersion < NODEJS_MINIMUM_VERSION) { // check Node.js version console.log("Failed to start JSAN as the minimum required Node.js version cannot be found!"); console.log("Minimum version: " + NODEJS_MINIMUM_VERSION); - console.log("Your version: " + process.version.split(".")[0].substring(1)); + console.log("Your version: " + currentNodeVersion); process.exit(6633); } if (globals.getOption('stat')) { @@ -348,6 +335,8 @@ function analyzeMain() { try { analyzeMain(); -}catch (e) { + console.log("JSAN finished!") +} catch (e) { console.log(e); } + diff --git a/javascript/cl/JSAN/src/util/tree.js b/javascript/cl/JSAN/src/util/tree.js new file mode 100644 index 0000000..d2bf781 --- /dev/null +++ b/javascript/cl/JSAN/src/util/tree.js @@ -0,0 +1,24 @@ +class Node { + constructor(data, parent = null) { + this.data = data; + this.parent = parent; + this.children = []; + } +} + +class Tree { + constructor(data) { + this._root = new Node(data); + } + + add(data, parent) { + const child = new Node(data); + child.parent = parent; + parent.children.push(child); + return child; + } +} + +export { + Tree +} \ No newline at end of file diff --git a/javascript/cl/JSAN/src/util/util.js b/javascript/cl/JSAN/src/util/util.js new file mode 100644 index 0000000..cc7ac52 --- /dev/null +++ b/javascript/cl/JSAN/src/util/util.js @@ -0,0 +1,31 @@ +/** + * Check whether a parameter is undefined or null. + * + * Used in command line parsing. + * + * @param parameter + * @returns {boolean} + */ +export function isNull(parameter) { + return typeof parameter === "undefined" || parameter === null; +} + +/** + * Trim shebang to avoid parse error + * Doing it this way will preserve the original absolute positions + * This snippet is taken from: https://github.com/jquery/esprima/issues/1151#issuecomment-85706244 + * @param code the loaded code that might include starting shebang + * @returns the stripped source code + */ +export function trimHashbang(code) { + if (code.substring(0, 2) === '#!') { + let end = code.indexOf('\n'); + let filler = ''; + for (let i = 0; i < end; ++i) { + filler += ' '; + } + code = filler + code.substring(end, code.length); + console.log("Leading shebang was removed"); + } + return code; +} \ No newline at end of file diff --git a/javascript/cl/JSAN/webpack.common.js b/javascript/cl/JSAN/webpack.common.js new file mode 100644 index 0000000..206eaf2 --- /dev/null +++ b/javascript/cl/JSAN/webpack.common.js @@ -0,0 +1,31 @@ +const path = require('path'); +const webpack = require('webpack'); + + +module.exports = { + target: "node", + node: { + __dirname: false, + }, + entry: "./src/index.js", + output: { + filename: "JSAN.js", + path: path.resolve(__dirname, "dist") + }, + module: { + rules: [ + { + test: /\.node$/, + loader: "node-loader", + options: { + name: "[name].[ext]" + } + }, + ] + }, + plugins: [ + new webpack.BannerPlugin({ + banner: 'fullhash:[fullhash], chunkhash:[chunkhash], name:[name], base:[base], query:[query], file:[file]', + }) + ] +} diff --git a/javascript/cl/JSAN/webpack.dev.js b/javascript/cl/JSAN/webpack.dev.js new file mode 100644 index 0000000..efaf24e --- /dev/null +++ b/javascript/cl/JSAN/webpack.dev.js @@ -0,0 +1,7 @@ +const common = require('./webpack.common'); +const webpackMerge = require('webpack-merge'); + +module.exports = webpackMerge.merge(common, { + mode: "development", + //devtool: "none", +}); diff --git a/javascript/cl/JSAN/webpack.prod.js b/javascript/cl/JSAN/webpack.prod.js new file mode 100644 index 0000000..ffe330d --- /dev/null +++ b/javascript/cl/JSAN/webpack.prod.js @@ -0,0 +1,10 @@ +const common = require('./webpack.common'); +const webpackMerge = require('webpack-merge'); +const CleanWebpackPlugin = require('clean-webpack-plugin').CleanWebpackPlugin; + +module.exports = webpackMerge.merge(common, { + mode: "production", + plugins: [ + new CleanWebpackPlugin() + ] +}); diff --git a/lib/archivecpp/CMakeLists.txt b/lib/archivecpp/CMakeLists.txt new file mode 100644 index 0000000..8386d41 --- /dev/null +++ b/lib/archivecpp/CMakeLists.txt @@ -0,0 +1,12 @@ +set (LIBNAME archivecpp) + +set (SOURCES + src/ArchiveHandler.cpp + + inc/ArchiveHandler.h + inc/messages.h +) + +add_library (${LIBNAME} STATIC ${SOURCES}) +target_link_libraries (${LIBNAME} miniz) +set_visual_studio_project_folder(${LIBNAME} TRUE) diff --git a/lib/archivecpp/inc/ArchiveHandler.h b/lib/archivecpp/inc/ArchiveHandler.h new file mode 100644 index 0000000..ae87097 --- /dev/null +++ b/lib/archivecpp/inc/ArchiveHandler.h @@ -0,0 +1,91 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _ARCHCPP_AH_H_ +#define _ARCHCPP_AH_H_ + +#include +#include +#include +#include +#include + +class ZipArchiveEntry : public mz_zip_archive_file_stat +{ + public: + std::string GetFullName() const; + uint64_t GetUncompressedSize() const; + uint64_t GetCompressedSize() const; + uint32_t GetCrc32() const; + MZ_TIME_T GetLastWriteTime() const; + uint32_t GetIndex() const; +}; + + +class ZipArchive : public mz_zip_archive +{ + public: + bool IsInArchive(const std::string& fileName); + unsigned GetEntriesCount() const; + std::list GetEntries(); + std::shared_ptr GetEntry(unsigned index); + void Close(); + void ExtractFile(const std::string& fileName); + void ExtractFile(const std::string& fileName, const std::string& outputName); + void ExtractFile(unsigned index, const std::string& outputName); + void AddFile(const std::string& fileName); + void AddFile(const std::string& fileName, const std::string& inArchiveFileName); + void CopyAllFromZip(ZipArchive& srcZip); + void CopyFromZip(ZipArchive& srcZip, int index); + ~ZipArchive(); +}; + + +class ZipFile +{ + public: + static bool IsInArchive(const std::string& zipPath, const std::string& fileName); + static bool AddFile(const std::string& zipPath, const std::string& fileName); + static bool AddFile(const std::string& zipPath, const std::string& fileName, const std::string& inArchiveName); + static std::unique_ptr OpenForReading(const std::string& zipPath); + static std::unique_ptr OpenForWriting(const std::string& zipPath); + static void ExtractFile(const std::string& zipPath, const std::string& fileName); + static void ExtractFile(const std::string& zipPath, const std::string& fileName, const std::string& outputName); +}; + +class TemporalArhiveExtractor +{ + public: + TemporalArhiveExtractor(const std::string& archiveFilename, const std::string& directoryName = "", bool cleanup = true); + TemporalArhiveExtractor(const TemporalArhiveExtractor&) = delete; + const TemporalArhiveExtractor& operator=(const TemporalArhiveExtractor&) = delete; + TemporalArhiveExtractor(TemporalArhiveExtractor&&); + ~TemporalArhiveExtractor(); + + const std::list& getFileList() const; + void appendFileList(std::list& fileListToExtend) const; + + private: + std::list contentFileList; + std::string tempDirectoryName; + const bool cleanup; +}; + +#endif diff --git a/lib/archivecpp/inc/messages.h b/lib/archivecpp/inc/messages.h new file mode 100644 index 0000000..a2817e6 --- /dev/null +++ b/lib/archivecpp/inc/messages.h @@ -0,0 +1,36 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _ARCHCPP_M_H_ +#define _ARCHCPP_M_H_ + +#define CMSG_EX_ERROR_BUFFER_CREATE "Error : buffer can't be created :" +#define CMSG_EX_ERROR_OPEN_FILE(FILENAME) "Error: opening file :" + FILENAME +#define CMSG_EX_FAILED_DELETE "Error : in delete file :" +#define CMSG_EX_FAILED_RENAME "Error : in rename file :" +#define CMSG_EX_MISSING_FILE_TYPE_INFORMATION "Missing file type information " +#define CMSG_EX_CORRUPT_CONTENT "Error: content is corrupted" +#define CMSG_EX_FILE_NOT_EXIST "File isn't exist" +#define CMSG_ERROR_SET_FILE_STAMP common::WriteMsg::mlError, "Error about set file stamp\n" +#define CMSG_ERROR_GET_FILE_STAMP common::WriteMsg::mlError, "Error about get file stamp\n" +#define CMSG_EX_WRONG_BINARY_VERSION(BINVER_REQ, BINVER_FOUND) "Wrong binary version (" + BINVER_REQ + " required, " + BINVER_FOUND + " found)." +#define CMSG_MSG_ERROR_DURING_ADDING_TO_ARCHIVE_WARNING common::WriteMsg::mlDebug, "Error during adding to archive: %s\n" + +#endif diff --git a/lib/archivecpp/src/ArchiveHandler.cpp b/lib/archivecpp/src/ArchiveHandler.cpp new file mode 100644 index 0000000..b1fd41b --- /dev/null +++ b/lib/archivecpp/src/ArchiveHandler.cpp @@ -0,0 +1,279 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +#ifdef __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdelete-non-abstract-non-virtual-dtor" + #pragma clang diagnostic ignored "-Wtautological-undefined-compare" +#endif + +#include "archivecpp/inc/ArchiveHandler.h" +#include "archivecpp/inc/messages.h" +#include +#include +#include +#include + +using namespace std; + +std::string ZipArchiveEntry::GetFullName() const +{ + return m_filename; +} + +uint64_t ZipArchiveEntry::GetUncompressedSize() const +{ + return m_uncomp_size; +} + +uint64_t ZipArchiveEntry::GetCompressedSize() const +{ + return m_comp_size; +} + +uint32_t ZipArchiveEntry::GetCrc32() const +{ + return m_crc32; +} + +MZ_TIME_T ZipArchiveEntry::GetLastWriteTime() const +{ + return m_time; +} + +uint32_t ZipArchiveEntry::GetIndex() const +{ + return m_file_index; +} + +bool ZipArchive::IsInArchive(const std::string& fileName) +{ + return mz_zip_reader_locate_file(this, fileName.c_str(), nullptr, 0) != -1; +} + +unsigned ZipArchive::GetEntriesCount() const +{ + return m_total_files; +} + +std::list ZipArchive::GetEntries() +{ + std::list entries; + for (unsigned i = 0; i < GetEntriesCount(); ++i) + { + entries.push_back(ZipArchiveEntry()); + if (mz_zip_reader_file_stat(this, i, &entries.back()) == MZ_FALSE) + throw columbus::Exception(COLUMBUS_LOCATION, mz_zip_get_error_string(mz_zip_get_last_error(this))); + } + return entries; +} + +shared_ptr ZipArchive::GetEntry(unsigned index) +{ + auto archiveEntry = make_shared(); + if (mz_zip_reader_file_stat(this, index, archiveEntry.get()) == MZ_FALSE) + throw columbus::Exception(COLUMBUS_LOCATION, mz_zip_get_error_string(mz_zip_get_last_error(this))); + + return archiveEntry; +} + +void ZipArchive::Close() +{ + if (m_zip_mode == MZ_ZIP_MODE_WRITING) + if (mz_zip_writer_finalize_archive(this) == MZ_FALSE) + throw columbus::Exception(COLUMBUS_LOCATION, mz_zip_get_error_string(mz_zip_get_last_error(this))); + + + if (mz_zip_end(this) == MZ_FALSE) + throw columbus::Exception(COLUMBUS_LOCATION, mz_zip_get_error_string(mz_zip_get_last_error(this))); +} + +void ZipArchive::ExtractFile(const std::string& fileName) +{ + if (mz_zip_reader_extract_file_to_file(this, fileName.c_str(), fileName.c_str(), 0) == MZ_FALSE) + throw columbus::Exception(COLUMBUS_LOCATION, mz_zip_get_error_string(mz_zip_get_last_error(this))); +} + +void ZipArchive::ExtractFile(const std::string& fileName, const std::string& outputName) +{ + if (mz_zip_reader_extract_file_to_file(this, fileName.c_str(), outputName.c_str(), 0) == MZ_FALSE) + throw columbus::Exception(COLUMBUS_LOCATION, mz_zip_get_error_string(mz_zip_get_last_error(this))); +} + +void ZipArchive::ExtractFile(unsigned index, const std::string& outputName) +{ + if (mz_zip_reader_extract_to_file(this, index, outputName.c_str(), 0) == MZ_FALSE) + throw columbus::Exception(COLUMBUS_LOCATION, mz_zip_get_error_string(mz_zip_get_last_error(this))); +} + +void ZipArchive::AddFile(const std::string& fileName) +{ + if (mz_zip_writer_add_file(this, fileName.c_str(), fileName.c_str(), nullptr, 0, MZ_DEFAULT_COMPRESSION) == MZ_FALSE) + throw columbus::Exception(COLUMBUS_LOCATION, mz_zip_get_error_string(mz_zip_get_last_error(this))); +} + +void ZipArchive::AddFile(const std::string& fileName, const std::string& inArchiveFileName) +{ + if (mz_zip_writer_add_file(this, inArchiveFileName.c_str(), fileName.c_str(), nullptr, 0, MZ_DEFAULT_COMPRESSION) == MZ_FALSE) + throw columbus::Exception(COLUMBUS_LOCATION, mz_zip_get_error_string(mz_zip_get_last_error(this))); +} + +void ZipArchive::CopyAllFromZip(ZipArchive& srcZip) +{ + for (unsigned index = 0; index < srcZip.GetEntriesCount(); ++index) + if (mz_zip_writer_add_from_zip_reader(this, &srcZip, index) == MZ_FALSE) + throw columbus::Exception(COLUMBUS_LOCATION, mz_zip_get_error_string(mz_zip_get_last_error(this))); +} + +void ZipArchive::CopyFromZip(ZipArchive& srcZip, int index) +{ + if (mz_zip_writer_add_from_zip_reader(this, &srcZip, index) == MZ_FALSE) + throw columbus::Exception(COLUMBUS_LOCATION, mz_zip_get_error_string(mz_zip_get_last_error(this))); +} + +ZipArchive::~ZipArchive() +{ + mz_zip_end(this); +} + +bool ZipFile::IsInArchive(const std::string& zipPath, const std::string& fileName) +{ + return OpenForReading(zipPath)->IsInArchive(fileName); +} + +bool ZipFile::AddFile(const std::string& zipPath, const std::string& fileName) +{ + return AddFile(zipPath, fileName, fileName); +} + +bool ZipFile::AddFile(const std::string& zipPath, const std::string& fileName, const std::string& inArchiveName) +{ + string tempzipPath = zipPath + ".tmp"; + try { + auto tempzip = OpenForWriting(tempzipPath); + try { + auto srczip = OpenForReading(zipPath); + tempzip->CopyAllFromZip(*srczip); + srczip->Close(); + } + catch (const columbus::Exception& error) + { + common::WriteMsg::write(CMSG_MSG_ERROR_DURING_ADDING_TO_ARCHIVE_WARNING, error.getMessage().c_str()); + } + tempzip->AddFile(fileName, fileName); + tempzip->Close(); + remove(zipPath.c_str()); + rename(tempzipPath.c_str(), zipPath.c_str()); + } + catch (const columbus::Exception& error) + { + common::WriteMsg::write(CMSG_MSG_ERROR_DURING_ADDING_TO_ARCHIVE_WARNING, error.getMessage().c_str()); + return false; + } + return true; +} + +unique_ptr ZipFile::OpenForReading(const std::string& zipPath) +{ + auto archive = make_unique(); + mz_zip_zero_struct(archive.get()); + if (mz_zip_reader_init_file(archive.get(), zipPath.c_str(), 0) == MZ_FALSE) + throw columbus::Exception(COLUMBUS_LOCATION, mz_zip_get_error_string(mz_zip_get_last_error(archive.get()))); + + return archive; +} + +unique_ptr ZipFile::OpenForWriting(const std::string& zipPath) +{ + auto archive = make_unique(); + mz_zip_zero_struct(archive.get()); + if (mz_zip_writer_init_file_v2(archive.get(), zipPath.c_str(), 0, MZ_ZIP_FLAG_WRITE_ZIP64) == MZ_FALSE) + throw columbus::Exception(COLUMBUS_LOCATION, mz_zip_get_error_string(mz_zip_get_last_error(archive.get()))); + + return archive; +} + + +void ZipFile::ExtractFile(const std::string& zipPath, const std::string& fileName) +{ + OpenForReading(zipPath)->ExtractFile(fileName); +} + +void ZipFile::ExtractFile(const std::string& zipPath, const std::string& fileName, const std::string& outputName) +{ + OpenForReading(zipPath)->ExtractFile(fileName, outputName); +} + +TemporalArhiveExtractor::TemporalArhiveExtractor(const string& archiveFilename, const string& directoryName, bool cleanup) + : tempDirectoryName (directoryName.empty() ? common::getTemporaryName() : directoryName) + , cleanup (cleanup) +{ + common::makeDirectory(tempDirectoryName); + + auto zipArchive = ZipFile::OpenForReading(archiveFilename); + for (size_t entryIndex = 0; entryIndex < zipArchive->GetEntriesCount(); ++entryIndex) + { + auto zipEntry = zipArchive->GetEntry(entryIndex); + + /* Because the paths are too long, we have to do a little hack, and store these files with short paths as possible + im not sure if this is going to lead to conflicting filenames tho... (BUG) + + string filename = zipEntryPtr->GetFullName(); + + // We don't for sure, wether the filename stored in the zip is absolute or relative. + // So we must check, because in the end, we want to work with an absolute path. + if (common::pathIsRelative(filename)) + filename = tempDirectoryName + DIRDIVCHAR + filename; + + */ + // this is the hack, for shorter paths: (only get the filename from zip, without path) + string filename = tempDirectoryName + DIRDIVCHAR + common::pathFindFileName(zipEntry->GetFullName()); + string directoryname = common::pathRemoveFileSpec(filename); + + if (filename != directoryname) + common::makeDirectory(directoryname); + + contentFileList.push_back(filename); + zipArchive->ExtractFile(zipEntry->GetIndex(), filename); + } +} + +TemporalArhiveExtractor::TemporalArhiveExtractor(TemporalArhiveExtractor&& b) + : contentFileList(move(b.contentFileList)) + , tempDirectoryName(move(b.tempDirectoryName)) + , cleanup(b.cleanup) +{ +} + +TemporalArhiveExtractor::~TemporalArhiveExtractor() +{ + if (!tempDirectoryName.empty() && cleanup) + common::pathDeleteFile(tempDirectoryName, true); +} + +const std::list& TemporalArhiveExtractor::getFileList() const +{ + return contentFileList; +} + +void TemporalArhiveExtractor::appendFileList(std::list& fileListToExtend) const +{ + for (const auto& filename : contentFileList) + fileListToExtend.push_back(filename); +} diff --git a/lib/clangsupport/ASTFilter.cpp b/lib/clangsupport/ASTFilter.cpp new file mode 100644 index 0000000..ddde617 --- /dev/null +++ b/lib/clangsupport/ASTFilter.cpp @@ -0,0 +1,218 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "ASTFilter.h" +#include +#include "messages.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace clang; + + +namespace { + +using columbus::FilterState; +using clang::ASTPrePostVisitor; + +class FilterVisitor : public ASTPrePostVisitor +{ + public: + + FilterVisitor(const ASTContext& context, const DirectoryFilter& directoryFilter, map& nodeFilter, common::Cache *locationCache, const bool visitLambdaClosureClass, const bool visitTemplateInstantiations, const bool visitImplicitCode, const FilterState initialFilterState = FilterState::NotFiltered) + : context (context) + , directoryFilter (directoryFilter) + , nodeFilter (nodeFilter) + , locationCache (locationCache) + , visitLambdaClosureClass (visitLambdaClosureClass) + , visitTemplateInstantiations (visitTemplateInstantiations) + , visitImplicitCode (visitImplicitCode) + { + filterStateStack.push(initialFilterState); + } + + bool visitStmt(clang::Stmt *s) override + { + doFiltering(s, nullptr); + if (visitLambdaClosureClass) + { + LambdaExpr* lambdaExpr = dyn_cast(s); + if (lambdaExpr != nullptr && lambdaExpr->getLambdaClass()) + { + FilterVisitor closureClassVisitor(context, directoryFilter, nodeFilter, locationCache, visitLambdaClosureClass, visitTemplateInstantiations, visitImplicitCode, filterStateStack.top()); + clang::ASTPrePostTraverser(context, lambdaExpr->getLambdaClass(), closureClassVisitor, visitTemplateInstantiations, visitImplicitCode).run(); + } + } + return true; + } + + void visitEndStmt(Stmt *s) override + { + filterStateStack.pop(); + return; + } + + bool visitDecl(Decl *d) override + { + if (TranslationUnitDecl::classof(d)) + { + nodeFilter[d] = FilterState::NotFiltered; + filterStateStack.push(FilterState::NotFiltered); + } + else + doFiltering(d, d->getDeclContext() != nullptr ? cast(d->getDeclContext()) : nullptr); + return true; + } + + void visitEndDecl(Decl *d) override + { + filterStateStack.pop(); + return; + } + + private: + + template + string getLineInfo(T* node) + { + FullSourceLoc fullLocation = context.getFullLoc(node->getBeginLoc()); + + if (fullLocation.isValid()) + { + fullLocation = fullLocation.getFileLoc(); + if (fullLocation.getFileEntry()) + { + if (locationCache != nullptr) + { + const auto result = locationCache->getValue(fullLocation.getFileID()); + if (result.found) + return result.value; + else + { + string canonicalizedName = common::pathCanonicalize(fullLocation.getFileEntry()->getName().str()); + locationCache->setValue(fullLocation.getFileID(), canonicalizedName); + return canonicalizedName; + } + } + return common::pathCanonicalize(fullLocation.getFileEntry()->getName().str()); + } + else + { + return string(); + } + } + + return string(); + } + + template + void doFiltering(T* node, T* parent) + { + // check the semantic parent + if (parent != nullptr) + { + auto& semanticParentFilterState = nodeFilter[parent]; + if (semanticParentFilterState == FilterState::Filtered) + { + filterStateStack.push(FilterState::Filtered); + return; + } + + } + + // semantic parent does not exists or it is not filtered + // we should check te ast parent + auto astFilterState = filterStateStack.top(); + if (astFilterState == FilterState::Filtered) + { + filterStateStack.push(FilterState::Filtered); + return; + } + + // neither the semantic parent nor the ast parent is filtered + auto& filterState = nodeFilter[node]; + if (!directoryFilter.isFilteredOut(getLineInfo(node))) + filterState = FilterState::NotFiltered; + + filterStateStack.push(filterState); + } + + private: + + const ASTContext& context; + const DirectoryFilter& directoryFilter; + map& nodeFilter; + stack filterStateStack; + common::Cache *locationCache; + + const bool visitLambdaClosureClass; + const bool visitTemplateInstantiations; + const bool visitImplicitCode; + +}; + +} // anonymous + +namespace columbus +{ + +ASTFilter::ASTFilter(const string& filterFile, const ASTContext& astContext, const bool visitLambdaClosureClass, const bool visitTemplateInstantiations, const bool visitImplicitCode) + : ASTFilter(filterFile, astContext, nullptr, visitLambdaClosureClass, visitTemplateInstantiations, visitImplicitCode) +{ + +} + + +ASTFilter::ASTFilter(const string& filterFile, const ASTContext& astContext, common::Cache *locationCache, const bool visitLambdaClosureClass, const bool visitTemplateInstantiations, const bool visitImplicitCode) +{ + if (directoryFilter.openFilterFile(filterFile)) + { + hasFilterFile = true; + FilterVisitor visitor(astContext, directoryFilter, filter, locationCache, visitLambdaClosureClass, visitTemplateInstantiations, visitImplicitCode); + ASTPrePostTraverser(astContext, visitor, nullptr, visitTemplateInstantiations, visitImplicitCode).run(); + } + else + { + hasFilterFile = false; + common::WriteMsg::write(CMSG_FAILED_TO_LOAD_FILTER_FILE, filterFile.c_str()); + } +} + +FilterState ASTFilter::getFilterState(void* astNode) const +{ + if (!hasFilterFile) + return FilterState::NotFiltered; + + auto filterIterator = filter.find(astNode); + if (filterIterator != filter.end()) + return filterIterator->second; + + return FilterState::Filtered; +} + +} // columbus diff --git a/lib/clangsupport/ASTFilter.h b/lib/clangsupport/ASTFilter.h new file mode 100644 index 0000000..913e49e --- /dev/null +++ b/lib/clangsupport/ASTFilter.h @@ -0,0 +1,63 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _ASTFILTER_H_ +#define _ASTFILTER_H_ + +#include +#include +#include + +#include +#include + +namespace clang +{ + class ASTContext; +} + +namespace columbus +{ + +enum class FilterState +{ + Filtered, + NotFiltered +}; + +class ASTFilter +{ + public: + ASTFilter(const std::string& filterFile, const clang::ASTContext& astContext, bool visitLambdaClosureClass = false, bool visitTemplateInstantiations = false, bool visitImplicitCode = false); + ASTFilter(const std::string& filterFile, const clang::ASTContext& astContext, common::Cache* locationCache, bool visitLambdaClosureClass = false, bool visitTemplateInstantiations = false, bool visitImplicitCode = false); + FilterState getFilterState(void* astNode) const; + + const DirectoryFilter& getDirectoryFilter() const { return directoryFilter; } + private: + bool hasFilterFile; + + DirectoryFilter directoryFilter; + std::map filter; +}; + +} + + +#endif diff --git a/lib/clangsupport/ASTIDMapGenerator.cpp b/lib/clangsupport/ASTIDMapGenerator.cpp new file mode 100644 index 0000000..99bccc0 --- /dev/null +++ b/lib/clangsupport/ASTIDMapGenerator.cpp @@ -0,0 +1,67 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "ASTIDMapGenerator.h" +#include + +using namespace clang; + +namespace { + + class ASTNodeVisitor : public clang::RecursiveASTVisitor + { + public: + ASTNodeVisitor(columbus::NodeIDMaps& nodeIdMaps) + : nodeIdMaps(nodeIdMaps) + {} + + bool VisitStmt(clang::Stmt *s) + { + nodeIdMaps.node2id[s] = idCnt; + nodeIdMaps.id2node[idCnt] = std::make_pair(s, columbus::AstNodeType::STMT); + idCnt++; + return true; + } + + bool VisitDecl(clang::Decl *d) + { + nodeIdMaps.node2id[d] = idCnt; + nodeIdMaps.id2node[idCnt] = std::make_pair(d, columbus::AstNodeType::DECL); + idCnt++; + return true; + } + + private: + + columbus::NodeIDMaps& nodeIdMaps; + unsigned idCnt = 1; + }; + +} // anonymous namespace + +std::shared_ptr columbus::generateNodeIDMaps(const ASTContext& context) +{ + auto nodeIdMaps = std::make_shared(); + if (context.getTranslationUnitDecl() != nullptr) + { + ASTNodeVisitor(*nodeIdMaps).TraverseDecl(context.getTranslationUnitDecl()); + } + return nodeIdMaps; +} diff --git a/lib/limmetrics/inc/metrics/NII.h b/lib/clangsupport/ASTIDMapGenerator.h similarity index 59% rename from lib/limmetrics/inc/metrics/NII.h rename to lib/clangsupport/ASTIDMapGenerator.h index d77c04e..ed88cb7 100644 --- a/lib/limmetrics/inc/metrics/NII.h +++ b/lib/clangsupport/ASTIDMapGenerator.h @@ -18,22 +18,32 @@ * limitations under the Licence. */ -#ifndef _METRICS_NII_H_ -#define _METRICS_NII_H_ +#ifndef _ASTIDMAPGENERATOR_H +#define _ASTIDMAPGENERATOR_H -#include "../MetricHandler.h" +#include +#include -namespace columbus { namespace lim { namespace metrics { +namespace clang +{ + class ASTContext; +} - class NII : public MetricHandler { - public: - NII( bool enabled, SharedContainers* shared ); - protected: - const std::string& translateLevel( asg::Language language, const std::string& level ) const override; - private: - void fillIncomingMethodInvocations( const asg::logical::Method& method, std::set& incomingInvocations, bool withInstances ); +namespace columbus +{ + enum AstNodeType + { + STMT, + DECL }; -}}} + typedef struct + { + std::map node2id; + std::map> id2node; + } NodeIDMaps; + std::shared_ptr generateNodeIDMaps(const clang::ASTContext& context); + +} // namespace columbus #endif diff --git a/lib/clangsupport/ASTLoader.cpp b/lib/clangsupport/ASTLoader.cpp new file mode 100644 index 0000000..3d7ceac --- /dev/null +++ b/lib/clangsupport/ASTLoader.cpp @@ -0,0 +1,61 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "ASTLoader.h" + +#include +#include +#include + +using namespace std; + +namespace columbus +{ + + ASTWithNodeIDMaps loadAST(const string& astFilename, const bool cacheLast) + { + static pair last = { { nullptr, nullptr }, "" }; + ASTWithNodeIDMaps result = { nullptr, nullptr }; + + if (astFilename == last.second) + return last.first; + + clang::FileSystemOptions FileSystemOpts; + shared_ptr PCHContainerOps = make_shared(); + // TODO Check `new clang::DiagnosticOptions()` for memory leak + clang::IntrusiveRefCntPtr Diags = clang::CompilerInstance::createDiagnostics(new clang::DiagnosticOptions()); + + result.astUnit = clang::ASTUnit::LoadFromASTFile( + astFilename, PCHContainerOps->getRawReader(), clang::ASTUnit::LoadEverything, + Diags, FileSystemOpts, false, false, clang::CaptureDiagsKind::None, /* AllowPCHWithCompilerErrors = */ true, false); + + result.nodeIdMaps = generateNodeIDMaps(result.astUnit->getASTContext()); + + if (cacheLast) + { + last.first = result; + last.second = astFilename; + } + + return result; + } + +} + diff --git a/lib/clangsupport/ASTLoader.h b/lib/clangsupport/ASTLoader.h new file mode 100644 index 0000000..bf0823f --- /dev/null +++ b/lib/clangsupport/ASTLoader.h @@ -0,0 +1,46 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _ASTLOADER_H_ +#define _ASTLOADER_H_ + +#include +#include +#include "ASTIDMapGenerator.h" + +namespace clang +{ + class ASTUnit; +} + +namespace columbus +{ + typedef struct + { + std::shared_ptr astUnit; + std::shared_ptr nodeIdMaps; + } ASTWithNodeIDMaps; + + ASTWithNodeIDMaps loadAST(const std::string& astFilename, const bool cacheLast = false); + +} // namespace columbus + + +#endif diff --git a/lib/clangsupport/ASTSupport.cpp b/lib/clangsupport/ASTSupport.cpp new file mode 100644 index 0000000..110989e --- /dev/null +++ b/lib/clangsupport/ASTSupport.cpp @@ -0,0 +1,47 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "ASTSupport.h" +#include + +namespace columbus{ + using namespace std; + + //node can be one of Decl, Stmt, Type, TypeLoc, NestedNameSpecifier or NestedNameSpecifierLoc. TODO: others + clang::DynTypedNodeList getParents(clang::ASTContext* context, clang::DynTypedNode node){ + if(const clang::Decl* d = node.get()) + { + return context->getParents(*d); + + }else if(const clang::Stmt* s = node.get()) + { + return context->getParents(*s); + + }else if(const clang::Type* t = node.get()) + { + return context->getParents(*t); + + } + + return clang::DynTypedNodeList(clang::DynTypedNode::create(*(context->getTranslationUnitDecl()))); + } + + +} \ No newline at end of file diff --git a/lib/clangsupport/ASTSupport.h b/lib/clangsupport/ASTSupport.h new file mode 100644 index 0000000..b172e07 --- /dev/null +++ b/lib/clangsupport/ASTSupport.h @@ -0,0 +1,34 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _ASTSUPPORT_H_ +#define _ASTSUPPORT_H_ + +#include +#include + + +namespace columbus{ + + clang::DynTypedNodeList getParents(clang::ASTContext* context, clang::DynTypedNode node); + +} + +#endif diff --git a/lib/clangsupport/CANCommon.h b/lib/clangsupport/CANCommon.h new file mode 100644 index 0000000..4df27e7 --- /dev/null +++ b/lib/clangsupport/CANCommon.h @@ -0,0 +1,123 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _CAN_CANCOMMON_H +#define _CAN_CANCOMMON_H + +#include +#include +#include +#include +#include + +struct SourcePoint { + unsigned line, column; + + bool operator<(const SourcePoint& rhs) const + { + return std::tie(line, column) < std::tie(rhs.line, rhs.column); + } + bool operator==(const SourcePoint& rhs) const + { + return std::tie(line, column) == std::tie(rhs.line, rhs.column); + } +}; + +struct MyScope +{ + SourcePoint begin, end; + columbus::lim::asg::logical::Member* member; + + bool operator==(const MyScope& rhs) const + { + return std::tie(begin, end, member) == std::tie(rhs.begin, rhs.end, rhs.member); + } +}; + +struct ScopeGuard +{ + enum GuardType { BEGIN, END }; + + MyScope scope; + GuardType guardType; + + SourcePoint getSourcePoint() const + { + if (guardType == BEGIN) + return scope.begin; + else + return scope.end; + } + + bool operator<(const ScopeGuard& rhs) const + { + return getSourcePoint() < rhs.getSourcePoint(); + } +}; + +struct CommentData +{ + struct Compare + { + // Since the comment field is not used in the comparison it can be modified after a CommantData is inserted into a set. + // If the comparison is changed the insertion has to be modified in the loadCommentStructure function too! + bool operator()(const CommentData& lhs, const CommentData& rhs) const + { + if (lhs.begin.line != rhs.begin.line) + return lhs.begin.line < rhs.begin.line; + + return lhs.begin.column < rhs.begin.column; + } + }; + + SourcePoint begin, end; + + std::string text; + + unsigned numberOfLines() const + { + return end.line - begin.line + 1; + } + + bool overlaps(const CommentData& other) const + { + return this->begin.line == other.end.line || other.begin.line == this->end.line; + } + +}; + +class CANFilePathRenamer { + std::string &changePathFrom, &changePathTo; +public: + CANFilePathRenamer(std::string &changePathFrom, std::string &changePathTo) + : changePathFrom(changePathFrom), changePathTo(changePathTo) {} + + std::string changeToLIMCompatible(std::string filePath) { + std::string ret; + if (changePathFrom.empty()) + ret = filePath; + else + ret = common::replace(filePath.data(), changePathFrom.c_str(), changePathTo.c_str()); + if (ret.size() >= 2 && ret[1] == ':') + ret[0] = (char)tolower(ret[0]); + return ret; + } +}; +#endif \ No newline at end of file diff --git a/lib/clangsupport/CMakeLists.txt b/lib/clangsupport/CMakeLists.txt new file mode 100644 index 0000000..442c1d4 --- /dev/null +++ b/lib/clangsupport/CMakeLists.txt @@ -0,0 +1,19 @@ +set (LIBNAME clangsupport) + +set (SOURCES + ASTIDMapGenerator.cpp + ASTLoader.cpp + ASTFilter.cpp + ASTSupport.cpp + + ASTIDMapGenerator.h + ASTLoader.h + ASTFilter.h + ASTSupport.h + messages.h + CANCommon.h +) + +add_library (${LIBNAME} STATIC ${SOURCES}) +add_dependencies (${LIBNAME} lim common clang) +set_visual_studio_project_folder(${LIBNAME} TRUE) diff --git a/lib/clangsupport/messages.h b/lib/clangsupport/messages.h new file mode 100644 index 0000000..405f3eb --- /dev/null +++ b/lib/clangsupport/messages.h @@ -0,0 +1,32 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _CLANGSUPPORT_MESSAGES_H_ +#define _CLANGSUPPORT_MESSAGES_H_ + +#define CMSG_DIFFERENT_NUMBER_OF_VISITED_NODES common::WriteMsg::mlDebug, "Debug: Different number of nodes were visited during the preorder and postorder visit! (Pre:%lu Post:%lu)\n" +#define CMSG_MISSING_NODE_FORM_POSTORDER common::WriteMsg::mlDebug, "Debug: Missing node from postorder list: %p (0x%08X) " + +#define CMSG_EX_MERGE_FAILED "Failed to merge the preorder and postorder list!" +#define CMSG_FAILED_TO_LOAD_FILTER_FILE common::WriteMsg::mlWarning, "Warning: Failed to load filter file: %s\n" + + + +#endif diff --git a/lib/common/inc/Stat.h b/lib/common/inc/Stat.h index 21b8bb0..a040d48 100644 --- a/lib/common/inc/Stat.h +++ b/lib/common/inc/Stat.h @@ -29,6 +29,10 @@ #include #include +#ifdef __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wreturn-stack-address" +#endif namespace common { @@ -202,4 +206,8 @@ namespace common }; } +#ifdef __clang__ + #pragma clang diagnostic pop +#endif + #endif diff --git a/lib/controller/src/ProfileHandler.cpp b/lib/controller/src/ProfileHandler.cpp index 12cb0a1..d948bb5 100644 --- a/lib/controller/src/ProfileHandler.cpp +++ b/lib/controller/src/ProfileHandler.cpp @@ -321,7 +321,6 @@ namespace columbus { namespace controller { stack _tagStack; ProfileHandler::ToolSettings* _actualTool = nullptr; ProfileHandler::ProfileData& _profileData; - ReaderState _readerState; string _actualUDM; string _actualL2P; string _actualUDMConfig; @@ -332,7 +331,6 @@ namespace columbus { namespace controller { : XmlHandler() , _tagStack() , _profileData(profileData) - , _readerState(rsNone) , _actualUDM() , _actualUDMConfig() { diff --git a/lib/csharp/inc/Factory.h b/lib/csharp/inc/Factory.h index 04004a9..7521e5a 100644 --- a/lib/csharp/inc/Factory.h +++ b/lib/csharp/inc/Factory.h @@ -258,8 +258,8 @@ namespace columbus { namespace csharp { namespace asg { const_iterator(const const_iterator& otherit) :containerIt (otherit.containerIt),fact(otherit.fact){} const_iterator& operator++() {containerIt++; while (containerIt != fact->container.end() && ((*containerIt == NULL) || fact->getIsFiltered(*containerIt))) containerIt++; return *this;} const_iterator operator++(int) {const_iterator tmp(*this); operator++(); return tmp;} - bool operator==(const const_iterator& rhs) {return containerIt==rhs.containerIt;} - bool operator!=(const const_iterator& rhs) {return containerIt!=rhs.containerIt;} + bool operator==(const const_iterator& rhs) const {return containerIt==rhs.containerIt;} + bool operator!=(const const_iterator& rhs) const {return containerIt!=rhs.containerIt;} const base::Base* operator*() {return *containerIt;} friend class Factory; }; diff --git a/lib/genealogy/inc/Factory.h b/lib/genealogy/inc/Factory.h index b90057b..ffbab1b 100644 --- a/lib/genealogy/inc/Factory.h +++ b/lib/genealogy/inc/Factory.h @@ -241,8 +241,8 @@ namespace columbus { namespace genealogy { const_iterator(const const_iterator& otherit) :containerIt (otherit.containerIt),fact(otherit.fact){} const_iterator& operator++() {containerIt++; while (containerIt != fact->container.end() && ((*containerIt == NULL) )) containerIt++; return *this;} const_iterator operator++(int) {const_iterator tmp(*this); operator++(); return tmp;} - bool operator==(const const_iterator& rhs) {return containerIt==rhs.containerIt;} - bool operator!=(const const_iterator& rhs) {return containerIt!=rhs.containerIt;} + bool operator==(const const_iterator& rhs) const {return containerIt==rhs.containerIt;} + bool operator!=(const const_iterator& rhs) const {return containerIt!=rhs.containerIt;} const Base* operator*() {return *containerIt;} friend class Factory; }; diff --git a/lib/graphsupport/CMakeLists.txt b/lib/graphsupport/CMakeLists.txt index f7c0360..2e2399e 100644 --- a/lib/graphsupport/CMakeLists.txt +++ b/lib/graphsupport/CMakeLists.txt @@ -9,7 +9,6 @@ set (SOURCES src/MetricSum.cpp src/RulBuilder.cpp src/SarifExporter.cpp - src/SarifWriter.cpp inc/CsvExporter.h inc/GraphConstants.h @@ -18,9 +17,8 @@ set (SOURCES inc/messages.h inc/Metric.h inc/MetricSum.h - inc/RulBuilder.h + inc/RulBuilder.h inc/SarifExporter.h - inc/SarifWriter.h ) add_library (${LIBNAME} STATIC ${SOURCES}) diff --git a/lib/graphsupport/inc/SarifExporter.h b/lib/graphsupport/inc/SarifExporter.h index 0335fc4..7e7bb40 100644 --- a/lib/graphsupport/inc/SarifExporter.h +++ b/lib/graphsupport/inc/SarifExporter.h @@ -23,8 +23,7 @@ #include #include - -using namespace std; +#include namespace columbus { namespace graphsupport { @@ -34,7 +33,7 @@ namespace columbus { * \param graph [in], graph from file * \param filename [in] */ - void exportToSarif(graph::Graph& graph, const std::string& filename, const string& sarifSeverityLevel); + void exportToSarif(graph::Graph& graph, const std::string& filename, const std::string& sarifSeverityLevel); } } diff --git a/lib/graphsupport/inc/SarifWriter.h b/lib/graphsupport/inc/SarifWriter.h deleted file mode 100644 index 197ccf2..0000000 --- a/lib/graphsupport/inc/SarifWriter.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * This file is part of OpenStaticAnalyzer. - * - * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged - * - * Licensed under Version 1.2 of the EUPL (the "Licence"); - * - * You may not use this work except in compliance with the Licence. - * - * You may obtain a copy of the Licence in the LICENSE file or at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ - -/********************************************************************** -Copyright (c) 2013 by Matt Swain - -The MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -***********************************************************************/ - -#include -#include "jsoncpp/inc/writer.h" - -namespace Json { - class JSON_API SarifWriter : public Writer - { - public: - SarifWriter(std::string opencurly = "{", - std::string closecurly = "}", - std::string opensquare = "[", - std::string closesquare = "]", - std::string colon = ":", - std::string comma = ",", - std::string indent = " ", - int maxWidth = 0); - virtual ~SarifWriter() {} - - public: // overridden from Writer - virtual std::string write(const Value &root); - - private: - void writeValue(const Value &value, std::string &doc, bool forceSingleLine); - bool isMultiline(const Value &value); - void indent(); - void unindent(); - - std::string document_; - std::string indentString_; - std::string opencurly_; - std::string closecurly_; - std::string opensquare_; - std::string closesquare_; - std::string colon_; - std::string comma_; - std::string indent_; - int maxWidth_; - }; -} \ No newline at end of file diff --git a/lib/graphsupport/src/CsvExporter.cpp b/lib/graphsupport/src/CsvExporter.cpp index 11bb1fb..9de2c81 100644 --- a/lib/graphsupport/src/CsvExporter.cpp +++ b/lib/graphsupport/src/CsvExporter.cpp @@ -310,6 +310,7 @@ namespace columbus { namespace graphsupport { nodeTypeMetricsMap[graphconstants::NTYPE_LIM_CLASS].insert(warningMetricsWithoutCalculatedFor.begin(), warningMetricsWithoutCalculatedFor.end()); nodeTypeMetricsMap[graphconstants::NTYPE_LIM_ENUM].insert(warningMetricsWithoutCalculatedFor.begin(), warningMetricsWithoutCalculatedFor.end()); nodeTypeMetricsMap[graphconstants::NTYPE_LIM_INTERFACE].insert(warningMetricsWithoutCalculatedFor.begin(), warningMetricsWithoutCalculatedFor.end()); + nodeTypeMetricsMap[graphconstants::NTYPE_LIM_UNION].insert(warningMetricsWithoutCalculatedFor.begin(), warningMetricsWithoutCalculatedFor.end()); nodeTypeMetricsMap[graphconstants::NTYPE_LIM_STRUCTURE].insert(warningMetricsWithoutCalculatedFor.begin(), warningMetricsWithoutCalculatedFor.end()); nodeTypeMetricsMap[graphconstants::NTYPE_LIM_METHOD].insert(warningMetricsWithoutCalculatedFor.begin(), warningMetricsWithoutCalculatedFor.end()); nodeTypeMetricsMap[graphconstants::NTYPE_LIM_FUNCTION].insert(warningMetricsWithoutCalculatedFor.begin(), warningMetricsWithoutCalculatedFor.end()); @@ -324,6 +325,7 @@ namespace columbus { namespace graphsupport { } else if (asg == graphconstants::HEADER_ASG_VALUE_C) { nodeTypeMetricsMap[graphconstants::NTYPE_LIM_ENUM].insert(warningMetricsWithoutCalculatedFor.begin(), warningMetricsWithoutCalculatedFor.end()); nodeTypeMetricsMap[graphconstants::NTYPE_LIM_STRUCTURE].insert(warningMetricsWithoutCalculatedFor.begin(), warningMetricsWithoutCalculatedFor.end()); + nodeTypeMetricsMap[graphconstants::NTYPE_LIM_UNION].insert(warningMetricsWithoutCalculatedFor.begin(), warningMetricsWithoutCalculatedFor.end()); nodeTypeMetricsMap[graphconstants::NTYPE_LIM_FUNCTION].insert(warningMetricsWithoutCalculatedFor.begin(), warningMetricsWithoutCalculatedFor.end()); nodeTypeMetricsMap[graphconstants::NTYPE_LIM_ATTRIBUTE].insert(warningMetricsWithoutCalculatedFor.begin(), warningMetricsWithoutCalculatedFor.end()); nodeTypeMetricsMap[graphconstants::NTYPE_LIM_COMPONENT].insert(warningMetricsWithoutCalculatedFor.begin(), warningMetricsWithoutCalculatedFor.end()); diff --git a/lib/graphsupport/src/SarifExporter.cpp b/lib/graphsupport/src/SarifExporter.cpp index 5f39d5f..9a071f6 100644 --- a/lib/graphsupport/src/SarifExporter.cpp +++ b/lib/graphsupport/src/SarifExporter.cpp @@ -18,17 +18,20 @@ * limitations under the Licence. */ +#include +#include #include "io/inc/IO.h" #include "io/inc/messages.h" #include "../inc/GraphConstants.h" #include "../inc/SarifExporter.h" -#include "../inc/SarifWriter.h" #include "../inc/messages.h" #include "jsoncpp/inc/json.h" #include #include #include #include +#include +#include using namespace columbus::graph; using namespace columbus::graphsupport::graphconstants; @@ -42,6 +45,8 @@ namespace { const string SARIF_NAME_RUNS = "runs"; const string SARIF_NAME_TOOL = "tool"; const string SARIF_NAME_DRIVER = "driver"; + const string SARIF_NAME_DOWNLOADURI = "downloadUri"; + const string SARIF_NAME_SEMVER = "semanticVersion"; const string SARIF_NAME_NAME = "name"; const string SARIF_NAME_LANG = "language"; const string SARIF_NAME_RESULTS = "results"; @@ -52,6 +57,7 @@ namespace { const string SARIF_NAME_LEVEL = "level"; const string SARIF_NAME_RANK = "rank"; const string SARIF_NAME_HELPURI = "helpUri"; + const string SARIF_NAME_INFORMATION_URI = "informationUri"; const string SARIF_NAME_LOCATIONS = "locations"; const string SARIF_NAME_THREADFLOWLOCATION = "location"; const string SARIF_NAME_OCCURED = "occurrenceCount"; @@ -64,7 +70,7 @@ namespace { const string SARIF_NAME_COLUMN = "startColumn"; const string SARIF_NAME_ENDCOLUMN = "endColumn"; const string SARIF_NAME_CODEFLOWS = "codeFlows"; - const string SARIF_NAME_NESTINGLEVEL = "nestingLevel"; + const string SARIF_NAME_NESTINGLEVEL = "nestingLevel"; const string SARIF_NAME_EXECUTIONORDER = "executionOrder"; const string SARIF_NAME_THREADFLOWS = "threadFlows"; const string SARIF_NAME_TEXT = "text"; @@ -72,61 +78,84 @@ namespace { const string SARIF_NAME_MESSAGE = "message"; const string SARIF_NAME_SHORTDESC = "shortDescription"; const string SARIF_NAME_FULLDESC = "fullDescription"; + const string SARIF_NAME_DESCRIPTION = "description"; const string SARIF_NAME_DEFCONF = "defaultConfiguration"; const string SARIF_NAME_RELATIONS = "relationships"; const string SARIF_NAME_TARGET = "target"; const string SARIF_NAME_RULEINDEX = "ruleIndex"; + const string SARIF_NAME_RULEID = "ruleId"; + const string SARIF_NAME_BASE_LINE = "baselineState"; const string SARIF_NAME_ENABLED = "enabled"; const string SARIF_NAME_PROPERTIES = "properties"; + const string SARIF_NAME_IMPORTANCE = "importance"; - //Sarif values //versions available on https://github.com/oasis-tcs/sarif-spec/tree/master/Schemata + //Sarif values const string SARIF_VALUE_VERSION = "2.1.0"; - const string SARIF_VALUE_SCHEMA = "http://json.schemastore.org/sarif-2.1.0-rtm.1"; - const string SARIF_VALUE_NAME = "OpenStaticAnalyzer"; - const string SARIF_VALUE_LANG = "en-US"; + const string SARIF_VALUE_SCHEMA = "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json"; + const string SARIF_VALUE_NAME = "OpenStaticAnalyzer"; + const string SARIF_VALUE_LANG = "en-US"; + const string SARIF_VALUE_DOWNURI = "https://github.com/sed-inf-u-szeged/OpenStaticAnalyzer"; + const string SARIF_VALUE_SEMVER = PROJECT_VERSION + std::string("+") + REVISION_NUMBER; namespace SARIF_VALUE_PRIORITY { - const string none = "none"; - const string note = "note"; + const string none = "none"; + const string info = "note"; const string warning = "warning"; - const string error = "error"; + const string error = "error"; }; - - const string CloneClassIds[] = { - "CA_warning_CloneClass", - "CCO_warning_CloneClass", - "CEE_warning_CloneClass", - "CEG_warning_CloneClass", - "CE_warning_CloneClass", - "CI_warning_CloneClass", - "CLLOC_warning_CloneClass", - "CR_warning_CloneClass", - "CV_warning_CloneClass", - "NCR_warning_CloneClass" + namespace SARIF_VALUE_BASELINE { + const string NEW = "new"; + const string UNCHANGED = "unchanged"; + const string UPDATED = "updated"; + const string ABSENT = "absent"; }; - - const string customCloneClassId = "All_CloneClasses"; + namespace SARIF_VALUE_IMPORTANCE { + const string IMPORTANT = "important"; + const string ESSENTIAL = "essential"; + const string UNIMPORTANT = "unimportant"; + }; + + const string customCloneClassId = "All_CloneClasses"; const string customCloneClassName = "All CloneClasses"; - + // because OpenStaticAnalyzer-Linux generates a path starting with /, on the other hand windows generates a path starting with the drive name, e.g. C: - const string uriFile = - #ifdef __linux__ + const string uriFile = +#ifdef __linux__ "file://"; - #else +#else "file:///"; - #endif +#endif /** * \brief basic IO class for SARIF */ class SarifIO : public virtual columbus::io::IOBase { + private: + const char *resultLeftMargin = " "; + const char *ruleLeftMargin = " "; public: - SarifIO() {}; - ~SarifIO() {}; - - void writeData(const string& data) { + void writeData(const Json::Value& root, bool isRule = false) { + Json::StreamWriterBuilder builder; + builder["indentation"] = " "; if (!isOpen()) throw columbus::IOException(COLUMBUS_LOCATION, CMSG_EX_FILE_NOT_OPEN); - else *stream << data; + else { + std::unique_ptr writer(builder.newStreamWriter()); + common::updateMemoryStat(); + writer->write(root, stream.get(), isRule ? ruleLeftMargin : resultLeftMargin); + common::updateMemoryStat(); + flush(); + } + } + void writeData(const string &text) { + *stream << text; + } + void writeData(const char *text) { + *stream << text; + } + void writeData(const vector &text) { + for (auto &t : text) { + *stream << t; + } } }; @@ -141,7 +170,7 @@ namespace { const Attribute &componentHasTheRequiredAttribute(const Node &node, const Attribute::aType &aType, const string &name, const string &context) { Attribute::AttributeIterator attrItr = node.findAttribute(aType, name, context); if (attrItr.hasNext()) return attrItr.next(); - const string type = aType == 0 ? "int" : aType == 1 ? "float" : aType == 2 ? "string" : aType == 3 ? "composite" : "invalid"; + const string type = aType == Attribute::atInt ? "int" : aType == Attribute::atFloat ? "float" : aType == Attribute::atString ? "string" : aType == Attribute::atComposite ? "composite" : "invalid"; throw columbus::Exception(COLUMBUS_LOCATION, CMSG_SARIF_OUT_OF_DATE(node.getUID(), type, name, context)); } @@ -153,10 +182,10 @@ namespace { * \param context [in], the context of the attribute of the given node * \return an Attribute reference */ - const Attribute &componentHasTheRequiredAttribute(AttributeComposite &attr, const Attribute::aType &aType, const string &name, const string &context){ + const Attribute &componentHasTheRequiredAttribute(AttributeComposite &attr, const Attribute::aType &aType, const string &name, const string &context) { Attribute::AttributeIterator attrItr = attr.findAttribute(aType, name, context); if (attrItr.hasNext()) return attrItr.next(); - const string type = aType == 0 ? "int" : aType == 1 ? "float" : aType == 2 ? "string" : aType == 3 ? "composite" : "invalid"; + const string type = aType == Attribute::atInt ? "int" : aType == Attribute::atFloat ? "float" : aType == Attribute::atString ? "string" : aType == Attribute::atComposite ? "composite" : "invalid"; throw columbus::Exception(COLUMBUS_LOCATION, CMSG_SARIF_OUT_OF_DATE("AttributeComposite", type, name, context)); } @@ -189,90 +218,127 @@ namespace { * \param attrComp [in], reference to AttributeComposite to which will be converted * \param location [in-out], refernce to Json::Value where the converted SARIF location will be stored */ - void writeLocation(AttributeComposite& attrComp, Json::Value &location) { - const Attribute &path = componentHasTheRequiredAttribute(attrComp, Attribute::atString, ATTR_PATH, ""); - const Attribute &lineBegin = componentHasTheRequiredAttribute(attrComp, Attribute::atInt, ATTR_LINE, ""); - const Attribute &lineEnd = componentHasTheRequiredAttribute(attrComp, Attribute::atInt, ATTR_ENDLINE, ""); - const Attribute &columnBegin = componentHasTheRequiredAttribute(attrComp, Attribute::atInt, ATTR_COLUMN, ""); - const Attribute &columnEnd = componentHasTheRequiredAttribute(attrComp, Attribute::atInt, ATTR_ENDCOLUMN, ""); - string pathTemp = uriFile + path.getStringValue(); - replace(pathTemp.begin(), pathTemp.end(), '\\', '/'); - - string lineBeginValue = lineBegin.getStringValue(); - string columnBeginValue = columnBegin.getStringValue(); - string lineEndValue = lineEnd.getStringValue(); - string columnEndValue = columnEnd.getStringValue(); + void writeLocation(AttributeComposite &attrComp, Json::Value &location) { + const AttributeString &path = (AttributeString&)componentHasTheRequiredAttribute(attrComp, Attribute::atString, ATTR_PATH, ""); + const AttributeInt &lineBegin = (AttributeInt&)componentHasTheRequiredAttribute(attrComp, Attribute::atInt, ATTR_LINE, ""); + const AttributeInt &lineEnd = (AttributeInt&)componentHasTheRequiredAttribute(attrComp, Attribute::atInt, ATTR_ENDLINE, ""); + const AttributeInt &columnBegin = (AttributeInt&)componentHasTheRequiredAttribute(attrComp, Attribute::atInt, ATTR_COLUMN, ""); + const AttributeInt &columnEnd = (AttributeInt&)componentHasTheRequiredAttribute(attrComp, Attribute::atInt, ATTR_ENDCOLUMN, ""); + + int line = lineBegin.getValue(); + int endLine = lineEnd.getValue(); + int column = columnBegin.getValue(); + int endColumn = columnEnd.getValue(); + std::string _path; + _path = uriFile + boost::filesystem::path(path.getStringValue()).generic_string(); + boost::replace_all(_path, " ", "%20"); // negative starting/ending value to 0, because sarif line/column number cannot have negative number - if (stoi(lineBeginValue) <= 0) { - lineBeginValue = "1"; + if (line <= 0) { + line = 1; } - if (stoi(lineEndValue) <= 0) { - lineEndValue = lineBeginValue; + if (endLine <= 0) { + endLine = line; } - if (stoi(columnBeginValue) <= 0) { - columnBeginValue = "1"; + if (column <= 0) { + column = 1; } - if (stoi(columnEndValue) <= 0) { - columnEndValue = columnBeginValue; + if (endColumn <= 0) { + endColumn = column; } - location[SARIF_NAME_PHLOCATION][SARIF_NAME_ARTLOCATION][SARIF_NAME_URI] = pathTemp; - location[SARIF_NAME_PHLOCATION][SARIF_NAME_REGION][SARIF_NAME_LINE] = stoi(lineBeginValue); - location[SARIF_NAME_PHLOCATION][SARIF_NAME_REGION][SARIF_NAME_COLUMN] = stoi(columnBeginValue); - location[SARIF_NAME_PHLOCATION][SARIF_NAME_REGION][SARIF_NAME_ENDLINE] = stoi(lineEndValue); - location[SARIF_NAME_PHLOCATION][SARIF_NAME_REGION][SARIF_NAME_ENDCOLUMN] = stoi(columnEndValue); + location[SARIF_NAME_PHLOCATION][SARIF_NAME_ARTLOCATION][SARIF_NAME_URI] = _path; + + location[SARIF_NAME_PHLOCATION][SARIF_NAME_REGION][SARIF_NAME_LINE] = line; + location[SARIF_NAME_PHLOCATION][SARIF_NAME_REGION][SARIF_NAME_COLUMN] = column; + location[SARIF_NAME_PHLOCATION][SARIF_NAME_REGION][SARIF_NAME_ENDLINE] = endLine; + location[SARIF_NAME_PHLOCATION][SARIF_NAME_REGION][SARIF_NAME_ENDCOLUMN] = endColumn; } - bool replace(string& str, const string from, const string end, const string to) { - size_t startPos = str.find(from); - if(startPos == std::string::npos) - return false; - size_t endPos = str.find(end, startPos + 2) + 1; - str.replace(startPos, endPos - startPos, to); - return true; + void writeLocation(const Node &node, Json::Value &location) { + writeLocation((AttributeComposite&)node.findAttribute(Attribute::atComposite, ATTR_POSITION, CONTEXT_ATTRIBUTE).next(), location); } - + + void replace(string& str, pair opening, pair closing) { + // example : opening={"
","```"}, closing={"
","```"} + + // opFirst = "" or "
" (html attributes, like id, class,...)
+    // group 2 : match everything after the first group
+    // group 3 : first occurence of "
" or "" (html attributes like id, class, .... This usually doesn't happen) + string reg = opFirst + "(" + opLast + "| .*?" + opLast + ")(.*?)?\\" + clFirst[0] + "\\" + clFirst.substr(1, clFirst.length()) + "(" + clLast + "| .+?" + clLast + ")"; + regex r(reg); + + // replaceText = "```Group2```"; + string replaceText = opening.second + "$2" + closing.second; + str = std::regex_replace(str, r, replaceText, regex_constants::match_not_eol); + } + /** * \brief convert basic html text to Github Flavored Markdown * \param sourceHtml [in-out], reference to source text, also the output for GFM */ - void htmlToGFM(string &sourceHtml, const string &asg){ - const string htmlTags[] = { - "

" , "

", - "", "", "", "", - "" , "", "" , "", - "
    " , "
", "
  • ", "
  • ", - "
    " , "" , "
    " , "" , "
    " , "", - """ , "<" , ">", "\n", "\\n", "'", "&" - }, GFMTags[] = { - "", "\n", - "**", "**", "**", "**", - "*", "*", "*", "*", - "\n", "", "* ", "\n", - "", "", "", "", "`", "```\n", - "\"", "<" , ">", "\n" , "\n", "'", "&" + string htmlToGFM(string sourceHtml, const string &asg) { + // newline is replaced by
    and not as \n, because \n confuses the regex + const map, pair> htmlToGFMTags{ + + {{"

    ", ""},{"

    ", "
    "}}, + {{"", "**"},{"", "**"}}, + {{"", "**"},{"", "**"}}, + {{"", "*"},{"", "*"}}, + {{"", "*"}, {"", "*"}}, + {{"
      ", "
      "}, {"
    ", ""}}, + {{"
  • ", "* "}, {"
  • ", "
    "}}, + {{"
    ", ""}, {"
    ", ""}}, + {{"", ""}, {"", ""}}, + {{"", "`"}, {"", "`"}}, + {{"
    ", "```"}, {"
    ", "```"}}, + {{"

    ","# "}, {"

    ",""}}, + {{"

    ","## "}, {"

    ",""}}, + {{"

    ","### "}, {"

    ",""}}, + {{"

    ","#### "}, {"

    ",""}}, + {{"
    ","##### "}, {"
    ",""}}, + {{"
    ","###### "}, {"
    ",""}}, + }; + const map unicodeToGFMTags{ + {""", "\""}, + {"<", "<"}, + {">", ">"}, + {"\\n", "\n"}, + {"'", "'"}, + {"&", "&"}, + {"\u2013", "-"} }; - int size = 27; // Html links to Markdown links - while(sourceHtml.find(" html tag - while(positionStart <= positionEnd - 1){ + while (positionStart <= positionEnd - 1) { linkHref += sourceHtml.at(positionStart); positionStart++; } - + positionStart = sourceHtml.find(">", positionEnd) + 1; positionEnd = sourceHtml.find("", positionStart) - 1; string linkText = ""; //get the text from the html tag - while(positionStart <= positionEnd){ + while (positionStart <= positionEnd) { linkText += sourceHtml.at(positionStart); positionStart++; } @@ -280,24 +346,24 @@ namespace { sourceHtml.replace(saveStart, positionEnd - saveStart + 5, link); } - //simple tags that doesnt have class, id, data, ... attributes - for (int i = 0; i < size; i++){ - boost::replace_all(sourceHtml, htmlTags[i], GFMTags[i]); + for (const auto &tag : unicodeToGFMTags) { + boost::replace_all(sourceHtml, tag.first, tag.second); + } + //have to replace line breaks with a placeholder value, because the regex library cant handle new lines + boost::replace_all(sourceHtml, "\n", "
    "); + for (const auto &tag : htmlToGFMTags) { + replace(sourceHtml, tag.first, tag.second); } - //code tags that have class, id, data, ... attributes - while (replace(sourceHtml, "", "```")); - while (replace(sourceHtml, "", "`")); - //formatting the markdown code ``` - boost::replace_all(sourceHtml, "````", "```"); // this happens if
    ... exist
    -        boost::replace_first(sourceHtml, "```", "\n```" + asg + "\n");
    -        boost::replace_last(sourceHtml, "```", "\n```\n");
    -        // every remainig <> tag
    -        while (replace(sourceHtml, "<", ">", ""));
    -
    -        //Getting rid of excess line breaks
    -        boost::replace_all(sourceHtml, "\n\n\n", "\n\n"),
    -        boost::replace_all(sourceHtml, "\n\n\n\n", "\n\n"),
    +        replace(sourceHtml, { "````","\n```cpp\n" }, { "````", "\n```\n" }); // this happens if 
    ... exist
    +        boost::replace_all(sourceHtml, "
    ", "\n"); + boost::replace_tail(sourceHtml, 1, ""); + return sourceHtml; + } + + std::string getSmellType(const Node &node) { + AttributeString &ciSmellType = (AttributeString&)componentHasTheRequiredAttribute(node, Attribute::atString, ATTR_DCF_CLONESMELLTYPE, CONTEXT_ATTRIBUTE); + return ciSmellType.getStringValue(); } } @@ -316,46 +382,88 @@ namespace columbus { sarifSeverityLevel.find('c') != std::string::npos || sarifSeverityLevel.find('C') != std::string::npos }; - Json::Value root(Json::objectValue); + SarifIO sio; + sio.open(filename, io::IOBase::eOpenMode::omWrite); + + /* + * ----------------------------------------- README ------------------------------------------------------ + * Json value as a root has been removed beacause it consumes too much memory + * For a 5GB graph in memory, the Json::Value consumes an extra 10GB, and memory overflow can occure... + * Json::Value as shown below works just fine, its performance is acceptable, and its usage is clear, + * the only problem is memory consumption + * The "Json::Value root" has been replaced with sio.writeData(...) as an alternate solution to not store + * the data unnecessarily in the memory, since this library (jsoncpp) does not have an option to dump + * data constantly into a stream as we assign a value, we must resolve to a solution like this. + * I will leave this code here as a reference + * ------------------------------------------------------------------------------------------------------- + */ + + /*Json::Value root(Json::objectValue); root[SARIF_NAME_VERSION] = SARIF_VALUE_VERSION; root[SARIF_NAME_SCHEMA] = SARIF_VALUE_SCHEMA; root[SARIF_NAME_RUNS] = Json::arrayValue; root[SARIF_NAME_RUNS][0] = Json::objectValue; root[SARIF_NAME_RUNS][0][SARIF_NAME_TOOL][SARIF_NAME_DRIVER][SARIF_NAME_NAME] = SARIF_VALUE_NAME; root[SARIF_NAME_RUNS][0][SARIF_NAME_TOOL][SARIF_NAME_DRIVER][SARIF_NAME_LANG] = SARIF_VALUE_LANG; - root[SARIF_NAME_RUNS][0][SARIF_NAME_RESULTS] = Json::arrayValue; + root[SARIF_NAME_RUNS][0][SARIF_NAME_TOOL][SARIF_NAME_DRIVER][SARIF_NAME_VERSION] = PROJECT_VERSION; + root[SARIF_NAME_RUNS][0][SARIF_NAME_TOOL][SARIF_NAME_DRIVER][SARIF_NAME_DOWNLOADURI] = SARIF_VALUE_DOWNURI; + root[SARIF_NAME_RUNS][0][SARIF_NAME_TOOL][SARIF_NAME_DRIVER][SARIF_NAME_SEMVER] = SARIF_VALUE_SEMVER; + root[SARIF_NAME_RUNS][0][SARIF_NAME_RESULTS] = Json::arrayValue;*/ + + //quote a string + auto quoted = [](const std::string &str)->std::string { + return "\"" + str + "\""; + }; + sio.writeData({ + "{\n", + " " + quoted(SARIF_NAME_SCHEMA) + " : " + quoted(SARIF_VALUE_SCHEMA) + ",\n", + " " + quoted(SARIF_NAME_VERSION) + " : " + quoted(SARIF_VALUE_VERSION) + ",\n", + " " + quoted(SARIF_NAME_RUNS) + " :\n", + " [\n", + " {\n", + " " + quoted(SARIF_NAME_TOOL) + " :\n", + " {\n", + " " + quoted(SARIF_NAME_DRIVER) + " :\n", + " {\n", + " " + quoted(SARIF_NAME_NAME) + " : " + quoted(SARIF_VALUE_NAME) + ",\n", + " " + quoted(SARIF_NAME_LANG) + " : "+ quoted(SARIF_VALUE_LANG) +",\n", + " " + quoted(SARIF_NAME_VERSION) + " : " + quoted(PROJECT_VERSION) + ",\n", + " " + quoted(SARIF_NAME_DOWNLOADURI) + " : " + quoted(SARIF_VALUE_DOWNURI) + ",\n", + " " + quoted(SARIF_NAME_RULES) + " :\n", + " [", + }); + //Everything related to collect,write and store the rules from the graph map ruleIndexesInJson; { Node::NodeIterator ruleNodes = graph.findNodes(NTYPE_RUL_METRIC); - root[SARIF_NAME_RUNS][0][SARIF_NAME_TOOL][SARIF_NAME_DRIVER][SARIF_NAME_RULES] = Json::arrayValue; int ruleCounter = 0; boost::filesystem::path full_path(boost::filesystem::current_path().parent_path()); full_path /= "UsersGuide.html"; bool userGuideExist = boost::filesystem::exists(full_path); - string fullPathString = full_path.string(); + string fullPathString = full_path.generic_string(); fullPathString = uriFile + fullPathString; - - replace(fullPathString.begin(), fullPathString.end(), '\\', '/'); + if (userGuideExist) { + sio.writeData(" \"" + SARIF_NAME_INFORMATION_URI + "\" : \"" + fullPathString + "\",\n"); + } while (ruleNodes.hasNext()) { const Node &ruleNode = ruleNodes.next(); const string &description = componentHasTheRequiredAttribute(ruleNode, Attribute::atString, ATTR_RUL_DESCRIPTION, CONTEXT_RUL).getStringValue(); const bool ruleParent = componentHasTheRequiredAttribute(ruleNode, Attribute::atString, ATTR_RUL_WARNING, CONTEXT_RUL).getStringValue() == "true"; - + Json::Value rule(Json::objectValue); rule[SARIF_NAME_ID] = ruleNode.getUID(); rule[SARIF_NAME_NAME] = componentHasTheRequiredAttribute(ruleNode, Attribute::atString, ATTR_RUL_DISPLAYNAME, CONTEXT_RUL).getStringValue(); - if(description != ""){ + if (description != "") { rule[SARIF_NAME_SHORTDESC][SARIF_NAME_TEXT] = description; } - if(componentHasNonRequiredAttribute(ruleNode, Attribute::atString, ATTR_RUL_HELPTEXT, CONTEXT_RUL)){ + if (componentHasNonRequiredAttribute(ruleNode, Attribute::atString, ATTR_RUL_HELPTEXT, CONTEXT_RUL)) { const string &helpText = componentHasTheRequiredAttribute(ruleNode, Attribute::atString, ATTR_RUL_HELPTEXT, CONTEXT_RUL).getStringValue(); - string GFMText = helpText; + string GFMText = htmlToGFM(helpText, asg); rule[SARIF_NAME_FULLDESC][SARIF_NAME_TEXT] = helpText; - htmlToGFM(GFMText, asg); rule[SARIF_NAME_FULLDESC][SARIF_NAME_MARKDOWN] = GFMText; } @@ -363,11 +471,11 @@ namespace columbus { if (ruleParent) { AttributeComposite &ruleAttribute = (AttributeComposite&)componentHasTheRequiredAttribute(ruleNode, Attribute::atComposite, ATTR_RUL_SETTINGS, CONTEXT_RUL); - + if (componentHasNonRequiredAttribute(ruleAttribute, Attribute::atString, ATTR_RUL_PRIORITY, CONTEXT_RUL)) { string priority = componentHasTheRequiredAttribute(ruleAttribute, Attribute::atString, ATTR_RUL_PRIORITY, CONTEXT_RUL).getStringValue(); int rank = (priority == "Info" ? 0 : (priority == "Minor" ? 1 : (priority == "Major" ? 2 : (priority == "Critical" ? 3 : 4)))); - + // if the severity of the result is not required to be converted, then the rule will not be saved AttributeComposite& attrCalc = (AttributeComposite&)componentHasTheRequiredAttribute(ruleNode, Attribute::atComposite, ATTR_RUL_CALCULATED, CONTEXT_RUL); if (componentHasNonRequiredAttribute(attrCalc, Attribute::atString, ATTR_RUL_CALCULATEDFOR, CONTEXT_RUL)) { @@ -377,9 +485,9 @@ namespace columbus { rank = 5; } } - if(!sarifSeverityLevelVal[rank]) continue; + if (!sarifSeverityLevelVal[rank]) continue; - priority = (priority == "Info") ? SARIF_VALUE_PRIORITY::note : (priority == "Minor" || priority == "Major") ? SARIF_VALUE_PRIORITY::warning : SARIF_VALUE_PRIORITY::error; + priority = (priority == "Info") ? SARIF_VALUE_PRIORITY::info : (priority == "Minor" || priority == "Major") ? SARIF_VALUE_PRIORITY::warning : SARIF_VALUE_PRIORITY::error; rule[SARIF_NAME_DEFCONF][SARIF_NAME_LEVEL] = priority; rule[SARIF_NAME_DEFCONF][SARIF_NAME_RANK] = rank; } @@ -394,18 +502,20 @@ namespace columbus { rule[SARIF_NAME_HELPURI] = fullPathString + "#" + parentName; } } - else{ + else { if (userGuideExist) { rule[SARIF_NAME_HELPURI] = fullPathString + "#" + ruleNode.getUID(); } } - } else { continue; } if (componentHasTheRequiredAttribute(ruleNode, Attribute::atString, ATTR_RUL_GROUPTYPE, CONTEXT_RUL).getStringValue() != "summarized" && !rule[SARIF_NAME_DEFCONF][SARIF_NAME_RANK].empty() && !rule[SARIF_NAME_DEFCONF][SARIF_NAME_LEVEL].empty() && !rule[SARIF_NAME_DEFCONF][SARIF_NAME_ENABLED].empty() && rule[SARIF_NAME_DEFCONF][SARIF_NAME_ENABLED].asString() == "true") { - root[SARIF_NAME_RUNS][0][SARIF_NAME_TOOL][SARIF_NAME_DRIVER][SARIF_NAME_RULES][ruleCounter] = Json::Value(rule); + sio.writeData(rule, true); + sio.writeData(","); + ruleIndexesInJson.emplace(rule[SARIF_NAME_ID].asString(), ruleCounter); + common::updateMemoryStat(); ruleCounter++; } } @@ -419,16 +529,20 @@ namespace columbus { rule[SARIF_NAME_DEFCONF][SARIF_NAME_LEVEL] = "note"; rule[SARIF_NAME_DEFCONF][SARIF_NAME_RANK] = 5; - root[SARIF_NAME_RUNS][0][SARIF_NAME_TOOL][SARIF_NAME_DRIVER][SARIF_NAME_RULES][ruleCounter] = Json::Value(rule); + sio.writeData(rule); + ruleIndexesInJson.emplace(rule[SARIF_NAME_ID].asString(), ruleCounter); ruleCounter++; } - - //soft references to the rules, required to do this way, because this type of json formatter organize the elements by its name, and not by the order it was insterted - for (unsigned int index = 0; index < root[SARIF_NAME_RUNS][0][SARIF_NAME_TOOL][SARIF_NAME_DRIVER][SARIF_NAME_RULES].size(); index++) { - ruleIndexesInJson.insert(pair(root[SARIF_NAME_RUNS][0][SARIF_NAME_TOOL][SARIF_NAME_DRIVER][SARIF_NAME_RULES][index][SARIF_NAME_ID].asString(), index)); - } } + sio.writeData({ + "\n", + " ]\n", + " }\n", + " },\n", + " " + quoted(SARIF_NAME_RESULTS) + ":\n", + " [" + }); Node::NodeTypeSet types; @@ -460,64 +574,107 @@ namespace columbus { types.insert(NTYPE_RPG_PROGRAM); types.insert(NTYPE_RPG_MODULE); types.insert(NTYPE_RPG_PROCEDURE); - types.insert(NTYPE_RPG_SUBROUTINE); + types.insert(NTYPE_RPG_SUBROUTINE); types.insert(NTYPE_DCF_CLONEINSTANCE); } Node::NodeIterator allNodes = graph.findNodes(types); - int resultCounter = 0; + bool comma = false; // Goes through all the Nodes that has one of the Node type declared above while (allNodes.hasNext()) { - Node node = allNodes.next(); - string name = node.getUID(); - Node::NodeType type = node.getType(); + const Node &node = allNodes.next(); + const Node::NodeType &type = node.getType(); AttributeComposite::AttributeIterator attr = node.findAttributeByContext(CONTEXT_WARNING); + string smellType = SARIF_VALUE_BASELINE::NEW; + + // CloneClass changes + // CloneClass handling, add extra rule: All CloneClasses + if (type == NTYPE_DCF_CLONECLASS && ruleIndexesInJson.find(customCloneClassId) != ruleIndexesInJson.end()) { + Json::Value result; + const string &name = componentHasTheRequiredAttribute(node, Attribute::atString, ATTR_NAME, CONTEXT_ATTRIBUTE).getStringValue(); + Edge::EdgeIterator edges = node.findOutEdges(Edge::EdgeType(ETYPE_DCF_CLONETREE, Edge::edtDirectional)); + string cloneInstanceSmellType; + string cloneClassSmellType = getSmellType(node); + bool changed = false; + int locationsCounter = 0; + + // has to iterate through the clone instances again + while (edges.hasNext()) { + // CloneInstance + const Node &edgeNode = edges.next().getToNode(); + cloneInstanceSmellType = getSmellType(edgeNode); + + if (componentHasNonRequiredAttribute(edgeNode, Attribute::atComposite, ATTR_POSITION, CONTEXT_ATTRIBUTE)) { + Json::Value location; + writeLocation(edgeNode, location); + const string &name = componentHasTheRequiredAttribute(edgeNode, Attribute::atString, ATTR_NAME, CONTEXT_ATTRIBUTE).getStringValue(); + result[SARIF_NAME_LOCATIONS].append(location); + result[SARIF_NAME_LOCATIONS][result[SARIF_NAME_LOCATIONS].size() - 1][SARIF_NAME_PHLOCATION][SARIF_NAME_ARTLOCATION][SARIF_NAME_DESCRIPTION][SARIF_NAME_TEXT] = name + " location"; + } + if (cloneClassSmellType == "cstNone" && cloneInstanceSmellType != "cstNone") { + smellType = SARIF_VALUE_BASELINE::UPDATED; + changed = true; + } + + locationsCounter++; + } + if (cloneClassSmellType == "cstAppearing") smellType = SARIF_VALUE_BASELINE::NEW; + else if (cloneClassSmellType == "cstDisappearing") smellType = SARIF_VALUE_BASELINE::ABSENT; + else if (!changed) smellType = SARIF_VALUE_BASELINE::UNCHANGED; + + result[SARIF_NAME_RULEINDEX] = ruleIndexesInJson.find(customCloneClassId)->second; + result[SARIF_NAME_BASE_LINE] = smellType; + result[SARIF_NAME_RULEID] = customCloneClassId; + if (locationsCounter > 0) { + result[SARIF_NAME_KIND] = "pass"; + result[SARIF_NAME_OCCURED] = locationsCounter; + result[SARIF_NAME_MESSAGE][SARIF_NAME_TEXT] = name; + if (comma) sio.writeData(","); + sio.writeData(result); + comma = true; + common::updateMemoryStat(); + } + } // Warning handling (simple warnings, CloneClass warnings, CloneInstance warning) while (attr.hasNext()) { AttributeComposite& attrComp = (AttributeComposite&)attr.next(); const string &warningID = attrComp.getName(); Json::Value result = Json::objectValue; + const string &messageTextTemp = componentHasTheRequiredAttribute(attrComp, Attribute::atString, ATTR_WARNINGTEXT, "").getStringValue(); + int locationCounter = 0; // if the rule doesn't exist (becuase its not required by severity switch), then the current result will not be examined and will not be saved if (ruleIndexesInJson.find(warningID) == ruleIndexesInJson.end()) continue; - - //linking the rule object index - result[SARIF_NAME_RULEINDEX] = ruleIndexesInJson.find(warningID)->second; - result[SARIF_NAME_KIND] = "pass"; - result[SARIF_NAME_LOCATIONS] = Json::arrayValue; - - // MultiLocation Start - { - Json::Value location(Json::objectValue); - int locationCounter = 0; - // multiple location for the same result - if (type == NTYPE_DCF_CLONECLASS) { - Edge::EdgeIterator edges = node.findOutEdges(Edge::EdgeType(ETYPE_DCF_CLONETREE, Edge::edtDirectional)); - - while (edges.hasNext()) { - Node edgeNode = edges.next().getToNode(); - if (componentHasNonRequiredAttribute(edgeNode, Attribute::atComposite, ATTR_POSITION, CONTEXT_ATTRIBUTE)) { - AttributeComposite& attrComp = (AttributeComposite&)(edgeNode.findAttribute(Attribute::atComposite, ATTR_POSITION, CONTEXT_ATTRIBUTE).next()); - writeLocation(attrComp, location); - - result[SARIF_NAME_LOCATIONS][locationCounter] = Json::Value(location); - locationCounter++; - } + + // multiple location for the same result + if (type == NTYPE_DCF_CLONECLASS) { + Edge::EdgeIterator edges = node.findOutEdges(Edge::EdgeType(ETYPE_DCF_CLONETREE, Edge::edtDirectional)); + + while (edges.hasNext()) { + // CloneInstance + Node edgeNode = edges.next().getToNode(); + + if (componentHasNonRequiredAttribute(edgeNode, Attribute::atComposite, ATTR_POSITION, CONTEXT_ATTRIBUTE)) { + Json::Value location; + writeLocation(edgeNode, location); + const string &name = componentHasTheRequiredAttribute(edgeNode, Attribute::atString, ATTR_NAME, CONTEXT_ATTRIBUTE).getStringValue(); + result[SARIF_NAME_LOCATIONS][locationCounter] = location; + result[SARIF_NAME_LOCATIONS][locationCounter][SARIF_NAME_PHLOCATION][SARIF_NAME_ARTLOCATION][SARIF_NAME_DESCRIPTION][SARIF_NAME_TEXT] = name + " location"; + locationCounter++; } } - // only one location for the result / not a cloneclass - else { - writeLocation(attrComp, location); - result[SARIF_NAME_LOCATIONS][locationCounter] = Json::Value(location); - locationCounter++; - } - if (locationCounter == 0) continue; // if there is a cloneclass that has no valid instance (eg. the Instance is cstDisappearing) - result[SARIF_NAME_OCCURED] = locationCounter; } - const string &messageTextTemp = componentHasTheRequiredAttribute(attrComp, Attribute::atString, ATTR_WARNINGTEXT, "").getStringValue(); - + // only one location for the result / not a cloneclass + else { + Json::Value location; + writeLocation(attrComp, location); + result[SARIF_NAME_LOCATIONS][locationCounter] = location; + locationCounter++; + } + if (locationCounter == 0) continue; // if there is a cloneclass that has no valid instance (eg. the Instance is cstDisappearing) + // if the node has traceCallBack attribute if (componentHasNonRequiredAttribute(attrComp, Attribute::atComposite, ATTR_EXTRAINFO, CONTEXT_TRACE)) { AttributeComposite& attrExtraInfo = (AttributeComposite&)componentHasTheRequiredAttribute(attrComp, Attribute::atComposite, ATTR_EXTRAINFO, CONTEXT_TRACE); @@ -529,17 +686,23 @@ namespace columbus { Json::Value location(Json::objectValue); writeLocation(attrTraceComp, location); - + result[SARIF_NAME_CODEFLOWS][0][SARIF_NAME_THREADFLOWS][0][SARIF_NAME_LOCATIONS][executionOrder][SARIF_NAME_EXECUTIONORDER] = executionOrder; result[SARIF_NAME_CODEFLOWS][0][SARIF_NAME_THREADFLOWS][0][SARIF_NAME_LOCATIONS][executionOrder][SARIF_NAME_THREADFLOWLOCATION] = location; + result[SARIF_NAME_CODEFLOWS][0][SARIF_NAME_THREADFLOWS][0][SARIF_NAME_LOCATIONS][executionOrder][SARIF_NAME_IMPORTANCE] = SARIF_VALUE_IMPORTANCE::ESSENTIAL; + + const string path = boost::filesystem::path(uriFile + componentHasTheRequiredAttribute(attrTraceComp, Attribute::atString, ATTR_PATH, "").getStringValue()).generic_string(); + result[SARIF_NAME_CODEFLOWS][0][SARIF_NAME_THREADFLOWS][0][SARIF_NAME_LOCATIONS][executionOrder][SARIF_NAME_THREADFLOWLOCATION][SARIF_NAME_PHLOCATION][SARIF_NAME_ARTLOCATION][SARIF_NAME_URI] = path; - // sourcelink relative path to absolute path - boost::filesystem::path absolutePath(result[SARIF_NAME_LOCATIONS][0][SARIF_NAME_PHLOCATION][SARIF_NAME_ARTLOCATION][SARIF_NAME_URI].asString()); - string relativePath = componentHasTheRequiredAttribute(attrTraceComp, Attribute::atString, ATTR_PATH, "").getStringValue(); - replace(relativePath.begin(), relativePath.end(), '\\', '/'); - absolutePath.remove_filename(); - absolutePath += "/" + relativePath; - result[SARIF_NAME_CODEFLOWS][0][SARIF_NAME_THREADFLOWS][0][SARIF_NAME_LOCATIONS][executionOrder][SARIF_NAME_THREADFLOWLOCATION][SARIF_NAME_PHLOCATION][SARIF_NAME_ARTLOCATION][SARIF_NAME_URI] = absolutePath.string(); + // Add warningText or RoleName as threadflow message + if (componentHasNonRequiredAttribute(attrTraceComp, Attribute::atString, ATTR_WARNINGTEXT, "")) { + const string &warningText = ((AttributeString&)componentHasTheRequiredAttribute(attrTraceComp, Attribute::atString, ATTR_WARNINGTEXT, "")).getStringValue(); + result[SARIF_NAME_CODEFLOWS][0][SARIF_NAME_THREADFLOWS][0][SARIF_NAME_LOCATIONS][executionOrder][SARIF_NAME_THREADFLOWLOCATION][SARIF_NAME_MESSAGE][SARIF_NAME_TEXT] = warningText; + } + else if (componentHasNonRequiredAttribute(attrTraceComp, Attribute::atString, "RoleName", "")) { + const string &warningText = ((AttributeString&)componentHasTheRequiredAttribute(attrTraceComp, Attribute::atString, "RoleName", "")).getStringValue(); + result[SARIF_NAME_CODEFLOWS][0][SARIF_NAME_THREADFLOWS][0][SARIF_NAME_LOCATIONS][executionOrder][SARIF_NAME_THREADFLOWLOCATION][SARIF_NAME_MESSAGE][SARIF_NAME_TEXT] = warningText; + } if (componentHasNonRequiredAttribute(attrTraceComp, Attribute::atInt, ATTR_CALLSTACKDEPTH, "")) { const int callStackDepth = ((AttributeInt&)componentHasTheRequiredAttribute(attrTraceComp, Attribute::atInt, ATTR_CALLSTACKDEPTH, "")).getValue(); @@ -554,47 +717,29 @@ namespace columbus { } result[SARIF_NAME_MESSAGE][SARIF_NAME_TEXT] = messageTextTemp; - root[SARIF_NAME_RUNS][0][SARIF_NAME_RESULTS][resultCounter] = Json::Value(result); - resultCounter++; - } - - // CloneClass handling - if (type == NTYPE_DCF_CLONECLASS && ruleIndexesInJson.find(customCloneClassId) != ruleIndexesInJson.end()) { - Json::Value result = Json::objectValue; - Json::Value location(Json::objectValue); - int locationCounter = 0; - Edge::EdgeIterator edges = node.findOutEdges(Edge::EdgeType(ETYPE_DCF_CLONETREE, Edge::edtDirectional)); - const string &name = componentHasTheRequiredAttribute(node, Attribute::atString, ATTR_NAME, CONTEXT_ATTRIBUTE).getStringValue(); - - //linking the rule object index - result[SARIF_NAME_RULEINDEX] = ruleIndexesInJson.find(customCloneClassId)->second; - result[SARIF_NAME_LOCATIONS] = Json::arrayValue; - - while (edges.hasNext()) { - Node edgeNode = edges.next().getToNode(); - if (componentHasNonRequiredAttribute(edgeNode, Attribute::atComposite, ATTR_POSITION, CONTEXT_ATTRIBUTE)) { - AttributeComposite& attrComp = (AttributeComposite&)(edgeNode.findAttribute(Attribute::atComposite, ATTR_POSITION, CONTEXT_ATTRIBUTE).next()); - writeLocation(attrComp, location); + result[SARIF_NAME_RULEINDEX] = ruleIndexesInJson.find(warningID)->second; + result[SARIF_NAME_BASE_LINE] = smellType; + result[SARIF_NAME_OCCURED] = locationCounter; + result[SARIF_NAME_RULEID] = warningID; + result[SARIF_NAME_KIND] = "pass"; - result[SARIF_NAME_LOCATIONS][locationCounter] = Json::Value(location); - locationCounter++; - } - } - if (locationCounter > 0) { // if there is a cloneclass that has no valid instance (eg. the Instance is cstDisappearing) - result[SARIF_NAME_KIND] = "pass"; - result[SARIF_NAME_OCCURED] = locationCounter; - result[SARIF_NAME_MESSAGE][SARIF_NAME_TEXT] = name; - root[SARIF_NAME_RUNS][0][SARIF_NAME_RESULTS][resultCounter] = Json::Value(result); - resultCounter++; - } + if (comma) sio.writeData(","); + sio.writeData(result); + comma = true; + common::updateMemoryStat(); } + } - SarifIO sio; - sio.open(filename, io::IOBase::eOpenMode::omWrite); - Json::SarifWriter writer; - sio.writeData(writer.write(root)); - sio.close(); + sio.writeData({ + "\n", + " ]\n", + " }\n", + " ]\n", + "}" + }); + + common::updateMemoryStat(); } } -} \ No newline at end of file +} diff --git a/lib/graphsupport/src/SarifWriter.cpp b/lib/graphsupport/src/SarifWriter.cpp deleted file mode 100644 index 01b4c75..0000000 --- a/lib/graphsupport/src/SarifWriter.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* - * This file is part of OpenStaticAnalyzer. - * - * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged - * - * Licensed under Version 1.2 of the EUPL (the "Licence"); - * - * You may not use this work except in compliance with the Licence. - * - * You may obtain a copy of the Licence in the LICENSE file or at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ - -/********************************************************************** -Copyright (c) 2013 by Matt Swain - -The MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -***********************************************************************/ - -#include "jsoncpp/inc/json.h" -#include "../inc/SarifWriter.h" - -namespace Json{ - SarifWriter::SarifWriter(std::string opencurly, - std::string closecurly, - std::string opensquare, - std::string closesquare, - std::string colon, - std::string comma, - std::string indent, - int maxWidth) - : opencurly_(opencurly), closecurly_(closecurly), opensquare_(opensquare), closesquare_(closesquare), colon_(colon), comma_(comma), indent_(indent), maxWidth_(maxWidth) - { - } - - std::string - SarifWriter::write(const Value &root) - { - document_ = ""; - indentString_ = ""; - writeValue(root, document_, false); - document_ += "\n"; - return document_; - } - - void SarifWriter::writeValue(const Value &value, std::string &doc, bool forceSingleLine) - { - switch (value.type()) - { - case nullValue: - doc += "null"; - break; - case intValue: - doc += valueToString(value.asLargestInt()); - break; - case uintValue: - doc += valueToString(value.asLargestUInt()); - break; - case realValue: - doc += valueToString(value.asDouble()); - break; - case stringValue: - doc += valueToQuotedString(value.asCString()); - break; - case booleanValue: - doc += valueToString(value.asBool()); - break; - case arrayValue: - { - bool isMulti = false; - if (!forceSingleLine) - { - std::string valLine = ""; - writeValue(value, valLine, true); - if (valLine.length() > (size_t)maxWidth_) - { - isMulti = true; - } - else - { - doc += valLine; - break; - } - } - doc += opensquare_; - if (isMulti) - indent(); - for (unsigned int index = 0; index < value.size(); ++index) - { - if (isMulti) - { - doc += "\n"; - doc += indentString_; - } - writeValue(value[index], doc, false); - if (index < value.size() - 1) - doc += comma_; - } - if (isMulti) - { - unindent(); - doc += "\n"; - doc += indentString_; - } - doc += closesquare_; - } - break; - case objectValue: - { - bool isMulti = false; - if (!forceSingleLine) - { - std::string valLine = ""; - writeValue(value, valLine, true); - if (valLine.length() > (size_t)maxWidth_) - { - isMulti = true; - } - else - { - doc += valLine; - break; - } - } - Value::Members members(value.getMemberNames()); - doc += opencurly_; - if (isMulti) - indent(); - - if (value.isMember("version")){ - if (isMulti) - { - doc += "\n"; - doc += indentString_; - } - doc += valueToQuotedString("version"); - doc += colon_; - writeValue(value["version"], doc, forceSingleLine); - if (members.size() > 1){ - doc += comma_; - } - } - - for (Value::Members::iterator it = members.begin(); it != members.end(); ++it) - { - const std::string &name = *it; - if (name == "version") { - if( it+1 == members.end() ) - break; - doc += comma_; - continue; - } - if (isMulti) - { - doc += "\n"; - doc += indentString_; - } - doc += valueToQuotedString(name.c_str()); - doc += colon_; - writeValue(value[name], doc, forceSingleLine); - if (!(it + 1 == members.end()) && *(it+1) != "version") - doc += comma_; - } - if (isMulti) - { - unindent(); - doc += "\n"; - doc += indentString_; - } - doc += closecurly_; - } - break; - } - } - - void SarifWriter::indent() - { - indentString_ += indent_; - } - - void SarifWriter::unindent() - { - int idSize = int(indent_.size()); - int idsSize = int(indentString_.size()); - if (idsSize >= idSize) - indentString_.resize(idsSize - idSize); - } -} // namespace Json \ No newline at end of file diff --git a/lib/io/inc/ZippedIO.h b/lib/io/inc/ZippedIO.h index 3731547..7ccf72b 100644 --- a/lib/io/inc/ZippedIO.h +++ b/lib/io/inc/ZippedIO.h @@ -72,31 +72,31 @@ namespace columbus { namespace io { * \throw IOException if the the file is already closed or not opened. * \throw IOException if can't close the file */ - virtual void close(); + virtual void close() override; /** \brief Write long long 0 size of the following block into the current file position * set the blockSizePosition to the current file position */ - virtual void writeStartSizeOfBlock(); + virtual void writeStartSizeOfBlock() override; /** \brief Write the difference beetween the actual file positon and the BlockSizeposition as a file size to the storaged blockSizePosition */ - virtual void writeEndSizeOfBlock(); + virtual void writeEndSizeOfBlock() override; /** \brief skip the next length long data. \param length of the data */ - virtual void skipNext(std::streamsize length); + virtual void skipNext(std::streamsize length) override; /** * \brief set position to read * \param startPos startposition to read */ - virtual void setStartReadPosition(std::streampos& startPos); + virtual void setStartReadPosition(std::streampos& startPos) override; - virtual void setStartWritePosition( std::streampos& startPos); + virtual void setStartWritePosition( std::streampos& startPos) override; }; }} diff --git a/lib/io/src/BinaryIO.cpp b/lib/io/src/BinaryIO.cpp index 09fe1e7..a0ba368 100644 --- a/lib/io/src/BinaryIO.cpp +++ b/lib/io/src/BinaryIO.cpp @@ -561,7 +561,7 @@ namespace columbus { namespace io { } void BinaryIO::setEndianState(EndianType endianState) { - endianState = endianState; + this->endianState = endianState; } BinaryIO::EndianType BinaryIO::getEndianState() { diff --git a/lib/java/inc/Factory.h b/lib/java/inc/Factory.h index 74779b3..418e5c9 100644 --- a/lib/java/inc/Factory.h +++ b/lib/java/inc/Factory.h @@ -241,8 +241,8 @@ namespace columbus { namespace java { namespace asg { const_iterator(const const_iterator& otherit) :containerIt (otherit.containerIt),fact(otherit.fact){} const_iterator& operator++() {containerIt++; while (containerIt != fact->container.end() && ((*containerIt == NULL) || fact->getIsFiltered(*containerIt))) containerIt++; return *this;} const_iterator operator++(int) {const_iterator tmp(*this); operator++(); return tmp;} - bool operator==(const const_iterator& rhs) {return containerIt==rhs.containerIt;} - bool operator!=(const const_iterator& rhs) {return containerIt!=rhs.containerIt;} + bool operator==(const const_iterator& rhs) const {return containerIt==rhs.containerIt;} + bool operator!=(const const_iterator& rhs) const {return containerIt!=rhs.containerIt;} const base::Base* operator*() {return *containerIt;} friend class Factory; }; diff --git a/lib/javascript/CMakeLists.txt b/lib/javascript/CMakeLists.txt index 47f1925..46ff5af 100644 --- a/lib/javascript/CMakeLists.txt +++ b/lib/javascript/CMakeLists.txt @@ -81,16 +81,20 @@ set (SOURCES inc/expression/ArrowFunctionExpression.h src/expression/AssignmentExpression.cpp inc/expression/AssignmentExpression.h - src/expression/AssignmentProperty.cpp - inc/expression/AssignmentProperty.h src/expression/AwaitExpression.cpp inc/expression/AwaitExpression.h + src/expression/BigIntLiteral.cpp + inc/expression/BigIntLiteral.h src/expression/BinaryExpression.cpp inc/expression/BinaryExpression.h src/expression/BooleanLiteral.cpp inc/expression/BooleanLiteral.h src/expression/CallExpression.cpp inc/expression/CallExpression.h + src/expression/ChainElement.cpp + inc/expression/ChainElement.h + src/expression/ChainExpression.cpp + inc/expression/ChainExpression.h src/expression/ClassExpression.cpp inc/expression/ClassExpression.h src/expression/ConditionalExpression.cpp @@ -101,6 +105,8 @@ set (SOURCES inc/expression/FunctionExpression.h src/expression/Identifier.cpp inc/expression/Identifier.h + src/expression/ImportExpression.cpp + inc/expression/ImportExpression.h src/expression/Literal.cpp inc/expression/Literal.h src/expression/LogicalExpression.cpp @@ -117,6 +123,8 @@ set (SOURCES inc/expression/NumberLiteral.h src/expression/ObjectExpression.cpp inc/expression/ObjectExpression.h + src/expression/PrivateIdentifier.cpp + inc/expression/PrivateIdentifier.h src/expression/Property.cpp inc/expression/Property.h src/expression/RegExpLiteral.cpp @@ -215,6 +223,8 @@ set (SOURCES inc/structure/MethodDefinition.h src/structure/ModuleSpecifier.cpp inc/structure/ModuleSpecifier.h + src/structure/PropertyDefinition.cpp + inc/structure/PropertyDefinition.h inc/messages.h ) diff --git a/lib/javascript/addon/Factory.cc b/lib/javascript/addon/Factory.cc index c5b6695..cfd3d23 100644 --- a/lib/javascript/addon/Factory.cc +++ b/lib/javascript/addon/Factory.cc @@ -28,6 +28,8 @@ napi_value Factory::Init(napi_env env, napi_value& exports) { DECLARE_NAPI_METHOD("createCommentWrapper", createCommentWrapper), DECLARE_NAPI_METHOD("createModuleDeclarationWrapper", createModuleDeclarationWrapper), DECLARE_NAPI_METHOD("createVariableDeclaratorWrapper", createVariableDeclaratorWrapper), + DECLARE_NAPI_METHOD("createChainElementWrapper", createChainElementWrapper), + DECLARE_NAPI_METHOD("createPrivateIdentifierWrapper", createPrivateIdentifierWrapper), DECLARE_NAPI_METHOD("createPropertyWrapper", createPropertyWrapper), DECLARE_NAPI_METHOD("createSpreadElementWrapper", createSpreadElementWrapper), DECLARE_NAPI_METHOD("createSuperWrapper", createSuperWrapper), @@ -37,21 +39,24 @@ napi_value Factory::Init(napi_env env, napi_value& exports) { DECLARE_NAPI_METHOD("createSwitchCaseWrapper", createSwitchCaseWrapper), DECLARE_NAPI_METHOD("createClassBodyWrapper", createClassBodyWrapper), DECLARE_NAPI_METHOD("createMethodDefinitionWrapper", createMethodDefinitionWrapper), + DECLARE_NAPI_METHOD("createPropertyDefinitionWrapper", createPropertyDefinitionWrapper), DECLARE_NAPI_METHOD("createProgramWrapper", createProgramWrapper), DECLARE_NAPI_METHOD("createIdentifierWrapper", createIdentifierWrapper), DECLARE_NAPI_METHOD("createExportNamedDeclarationWrapper", createExportNamedDeclarationWrapper), DECLARE_NAPI_METHOD("createImportDeclarationWrapper", createImportDeclarationWrapper), + DECLARE_NAPI_METHOD("createCallExpressionWrapper", createCallExpressionWrapper), + DECLARE_NAPI_METHOD("createMemberExpressionWrapper", createMemberExpressionWrapper), DECLARE_NAPI_METHOD("createArrayExpressionWrapper", createArrayExpressionWrapper), DECLARE_NAPI_METHOD("createArrowFunctionExpressionWrapper", createArrowFunctionExpressionWrapper), DECLARE_NAPI_METHOD("createAssignmentExpressionWrapper", createAssignmentExpressionWrapper), DECLARE_NAPI_METHOD("createAwaitExpressionWrapper", createAwaitExpressionWrapper), DECLARE_NAPI_METHOD("createBinaryExpressionWrapper", createBinaryExpressionWrapper), - DECLARE_NAPI_METHOD("createCallExpressionWrapper", createCallExpressionWrapper), + DECLARE_NAPI_METHOD("createChainExpressionWrapper", createChainExpressionWrapper), DECLARE_NAPI_METHOD("createClassExpressionWrapper", createClassExpressionWrapper), DECLARE_NAPI_METHOD("createConditionalExpressionWrapper", createConditionalExpressionWrapper), DECLARE_NAPI_METHOD("createFunctionExpressionWrapper", createFunctionExpressionWrapper), + DECLARE_NAPI_METHOD("createImportExpressionWrapper", createImportExpressionWrapper), DECLARE_NAPI_METHOD("createLogicalExpressionWrapper", createLogicalExpressionWrapper), - DECLARE_NAPI_METHOD("createMemberExpressionWrapper", createMemberExpressionWrapper), DECLARE_NAPI_METHOD("createMetaPropertyWrapper", createMetaPropertyWrapper), DECLARE_NAPI_METHOD("createNewExpressionWrapper", createNewExpressionWrapper), DECLARE_NAPI_METHOD("createObjectExpressionWrapper", createObjectExpressionWrapper), @@ -62,12 +67,12 @@ napi_value Factory::Init(napi_env env, napi_value& exports) { DECLARE_NAPI_METHOD("createUnaryExpressionWrapper", createUnaryExpressionWrapper), DECLARE_NAPI_METHOD("createUpdateExpressionWrapper", createUpdateExpressionWrapper), DECLARE_NAPI_METHOD("createYieldExpressionWrapper", createYieldExpressionWrapper), + DECLARE_NAPI_METHOD("createBigIntLiteralWrapper", createBigIntLiteralWrapper), DECLARE_NAPI_METHOD("createBooleanLiteralWrapper", createBooleanLiteralWrapper), DECLARE_NAPI_METHOD("createNullLiteralWrapper", createNullLiteralWrapper), DECLARE_NAPI_METHOD("createNumberLiteralWrapper", createNumberLiteralWrapper), DECLARE_NAPI_METHOD("createRegExpLiteralWrapper", createRegExpLiteralWrapper), DECLARE_NAPI_METHOD("createStringLiteralWrapper", createStringLiteralWrapper), - DECLARE_NAPI_METHOD("createAssignmentPropertyWrapper", createAssignmentPropertyWrapper), DECLARE_NAPI_METHOD("createArrayPatternWrapper", createArrayPatternWrapper), DECLARE_NAPI_METHOD("createAssignmentPatternWrapper", createAssignmentPatternWrapper), DECLARE_NAPI_METHOD("createObjectPatternWrapper", createObjectPatternWrapper), @@ -235,6 +240,44 @@ napi_value Factory::createVariableDeclaratorWrapper(napi_env env, napi_callback_ return instance; } +napi_value Factory::createChainElementWrapper(napi_env env, napi_callback_info info) { + napi_status status; + napi_value jsthis; + status = napi_get_cb_info(env, info, 0, nullptr, &jsthis, nullptr); + assert(status == napi_ok); + + Factory* obj; + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + expression::ChainElement* node; + node = obj->factory->createChainElementNode(); + + + napi_value instance; + status = ChainElementWrapper::NewInstance(env, node, &instance); + + return instance; +} +napi_value Factory::createPrivateIdentifierWrapper(napi_env env, napi_callback_info info) { + napi_status status; + napi_value jsthis; + status = napi_get_cb_info(env, info, 0, nullptr, &jsthis, nullptr); + assert(status == napi_ok); + + Factory* obj; + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + expression::PrivateIdentifier* node; + node = obj->factory->createPrivateIdentifierNode(); + + + napi_value instance; + status = PrivateIdentifierWrapper::NewInstance(env, node, &instance); + + return instance; +} napi_value Factory::createPropertyWrapper(napi_env env, napi_callback_info info) { napi_status status; napi_value jsthis; @@ -406,6 +449,25 @@ napi_value Factory::createMethodDefinitionWrapper(napi_env env, napi_callback_in return instance; } +napi_value Factory::createPropertyDefinitionWrapper(napi_env env, napi_callback_info info) { + napi_status status; + napi_value jsthis; + status = napi_get_cb_info(env, info, 0, nullptr, &jsthis, nullptr); + assert(status == napi_ok); + + Factory* obj; + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + structure::PropertyDefinition* node; + node = obj->factory->createPropertyDefinitionNode(); + + + napi_value instance; + status = PropertyDefinitionWrapper::NewInstance(env, node, &instance); + + return instance; +} napi_value Factory::createProgramWrapper(napi_env env, napi_callback_info info) { napi_status status; napi_value jsthis; @@ -482,6 +544,44 @@ napi_value Factory::createImportDeclarationWrapper(napi_env env, napi_callback_i return instance; } +napi_value Factory::createCallExpressionWrapper(napi_env env, napi_callback_info info) { + napi_status status; + napi_value jsthis; + status = napi_get_cb_info(env, info, 0, nullptr, &jsthis, nullptr); + assert(status == napi_ok); + + Factory* obj; + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + expression::CallExpression* node; + node = obj->factory->createCallExpressionNode(); + + + napi_value instance; + status = CallExpressionWrapper::NewInstance(env, node, &instance); + + return instance; +} +napi_value Factory::createMemberExpressionWrapper(napi_env env, napi_callback_info info) { + napi_status status; + napi_value jsthis; + status = napi_get_cb_info(env, info, 0, nullptr, &jsthis, nullptr); + assert(status == napi_ok); + + Factory* obj; + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + expression::MemberExpression* node; + node = obj->factory->createMemberExpressionNode(); + + + napi_value instance; + status = MemberExpressionWrapper::NewInstance(env, node, &instance); + + return instance; +} napi_value Factory::createArrayExpressionWrapper(napi_env env, napi_callback_info info) { napi_status status; napi_value jsthis; @@ -577,7 +677,7 @@ napi_value Factory::createBinaryExpressionWrapper(napi_env env, napi_callback_in return instance; } -napi_value Factory::createCallExpressionWrapper(napi_env env, napi_callback_info info) { +napi_value Factory::createChainExpressionWrapper(napi_env env, napi_callback_info info) { napi_status status; napi_value jsthis; status = napi_get_cb_info(env, info, 0, nullptr, &jsthis, nullptr); @@ -587,12 +687,12 @@ napi_value Factory::createCallExpressionWrapper(napi_env env, napi_callback_info status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); assert(status == napi_ok); - expression::CallExpression* node; - node = obj->factory->createCallExpressionNode(); + expression::ChainExpression* node; + node = obj->factory->createChainExpressionNode(); napi_value instance; - status = CallExpressionWrapper::NewInstance(env, node, &instance); + status = ChainExpressionWrapper::NewInstance(env, node, &instance); return instance; } @@ -653,7 +753,7 @@ napi_value Factory::createFunctionExpressionWrapper(napi_env env, napi_callback_ return instance; } -napi_value Factory::createLogicalExpressionWrapper(napi_env env, napi_callback_info info) { +napi_value Factory::createImportExpressionWrapper(napi_env env, napi_callback_info info) { napi_status status; napi_value jsthis; status = napi_get_cb_info(env, info, 0, nullptr, &jsthis, nullptr); @@ -663,16 +763,16 @@ napi_value Factory::createLogicalExpressionWrapper(napi_env env, napi_callback_i status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); assert(status == napi_ok); - expression::LogicalExpression* node; - node = obj->factory->createLogicalExpressionNode(); + expression::ImportExpression* node; + node = obj->factory->createImportExpressionNode(); napi_value instance; - status = LogicalExpressionWrapper::NewInstance(env, node, &instance); + status = ImportExpressionWrapper::NewInstance(env, node, &instance); return instance; } -napi_value Factory::createMemberExpressionWrapper(napi_env env, napi_callback_info info) { +napi_value Factory::createLogicalExpressionWrapper(napi_env env, napi_callback_info info) { napi_status status; napi_value jsthis; status = napi_get_cb_info(env, info, 0, nullptr, &jsthis, nullptr); @@ -682,12 +782,12 @@ napi_value Factory::createMemberExpressionWrapper(napi_env env, napi_callback_in status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); assert(status == napi_ok); - expression::MemberExpression* node; - node = obj->factory->createMemberExpressionNode(); + expression::LogicalExpression* node; + node = obj->factory->createLogicalExpressionNode(); napi_value instance; - status = MemberExpressionWrapper::NewInstance(env, node, &instance); + status = LogicalExpressionWrapper::NewInstance(env, node, &instance); return instance; } @@ -881,6 +981,25 @@ napi_value Factory::createYieldExpressionWrapper(napi_env env, napi_callback_inf return instance; } +napi_value Factory::createBigIntLiteralWrapper(napi_env env, napi_callback_info info) { + napi_status status; + napi_value jsthis; + status = napi_get_cb_info(env, info, 0, nullptr, &jsthis, nullptr); + assert(status == napi_ok); + + Factory* obj; + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + expression::BigIntLiteral* node; + node = obj->factory->createBigIntLiteralNode(); + + + napi_value instance; + status = BigIntLiteralWrapper::NewInstance(env, node, &instance); + + return instance; +} napi_value Factory::createBooleanLiteralWrapper(napi_env env, napi_callback_info info) { napi_status status; napi_value jsthis; @@ -976,25 +1095,6 @@ napi_value Factory::createStringLiteralWrapper(napi_env env, napi_callback_info return instance; } -napi_value Factory::createAssignmentPropertyWrapper(napi_env env, napi_callback_info info) { - napi_status status; - napi_value jsthis; - status = napi_get_cb_info(env, info, 0, nullptr, &jsthis, nullptr); - assert(status == napi_ok); - - Factory* obj; - status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); - assert(status == napi_ok); - - expression::AssignmentProperty* node; - node = obj->factory->createAssignmentPropertyNode(); - - - napi_value instance; - status = AssignmentPropertyWrapper::NewInstance(env, node, &instance); - - return instance; -} napi_value Factory::createArrayPatternWrapper(napi_env env, napi_callback_info info) { napi_status status; napi_value jsthis; diff --git a/lib/javascript/addon/Factory.h b/lib/javascript/addon/Factory.h index 4ff6373..c3f8c62 100644 --- a/lib/javascript/addon/Factory.h +++ b/lib/javascript/addon/Factory.h @@ -29,6 +29,8 @@ #include "inc/CommentWrapper.h" #include "inc/ModuleDeclarationWrapper.h" #include "inc/VariableDeclaratorWrapper.h" +#include "inc/ChainElementWrapper.h" +#include "inc/PrivateIdentifierWrapper.h" #include "inc/PropertyWrapper.h" #include "inc/SpreadElementWrapper.h" #include "inc/SuperWrapper.h" @@ -38,21 +40,24 @@ #include "inc/SwitchCaseWrapper.h" #include "inc/ClassBodyWrapper.h" #include "inc/MethodDefinitionWrapper.h" +#include "inc/PropertyDefinitionWrapper.h" #include "inc/ProgramWrapper.h" #include "inc/IdentifierWrapper.h" #include "inc/ExportNamedDeclarationWrapper.h" #include "inc/ImportDeclarationWrapper.h" +#include "inc/CallExpressionWrapper.h" +#include "inc/MemberExpressionWrapper.h" #include "inc/ArrayExpressionWrapper.h" #include "inc/ArrowFunctionExpressionWrapper.h" #include "inc/AssignmentExpressionWrapper.h" #include "inc/AwaitExpressionWrapper.h" #include "inc/BinaryExpressionWrapper.h" -#include "inc/CallExpressionWrapper.h" +#include "inc/ChainExpressionWrapper.h" #include "inc/ClassExpressionWrapper.h" #include "inc/ConditionalExpressionWrapper.h" #include "inc/FunctionExpressionWrapper.h" +#include "inc/ImportExpressionWrapper.h" #include "inc/LogicalExpressionWrapper.h" -#include "inc/MemberExpressionWrapper.h" #include "inc/MetaPropertyWrapper.h" #include "inc/NewExpressionWrapper.h" #include "inc/ObjectExpressionWrapper.h" @@ -63,12 +68,12 @@ #include "inc/UnaryExpressionWrapper.h" #include "inc/UpdateExpressionWrapper.h" #include "inc/YieldExpressionWrapper.h" +#include "inc/BigIntLiteralWrapper.h" #include "inc/BooleanLiteralWrapper.h" #include "inc/NullLiteralWrapper.h" #include "inc/NumberLiteralWrapper.h" #include "inc/RegExpLiteralWrapper.h" #include "inc/StringLiteralWrapper.h" -#include "inc/AssignmentPropertyWrapper.h" #include "inc/ArrayPatternWrapper.h" #include "inc/AssignmentPatternWrapper.h" #include "inc/ObjectPatternWrapper.h" @@ -122,6 +127,8 @@ class Factory { static napi_value createCommentWrapper(napi_env env, napi_callback_info info); static napi_value createModuleDeclarationWrapper(napi_env env, napi_callback_info info); static napi_value createVariableDeclaratorWrapper(napi_env env, napi_callback_info info); + static napi_value createChainElementWrapper(napi_env env, napi_callback_info info); + static napi_value createPrivateIdentifierWrapper(napi_env env, napi_callback_info info); static napi_value createPropertyWrapper(napi_env env, napi_callback_info info); static napi_value createSpreadElementWrapper(napi_env env, napi_callback_info info); static napi_value createSuperWrapper(napi_env env, napi_callback_info info); @@ -131,21 +138,24 @@ class Factory { static napi_value createSwitchCaseWrapper(napi_env env, napi_callback_info info); static napi_value createClassBodyWrapper(napi_env env, napi_callback_info info); static napi_value createMethodDefinitionWrapper(napi_env env, napi_callback_info info); + static napi_value createPropertyDefinitionWrapper(napi_env env, napi_callback_info info); static napi_value createProgramWrapper(napi_env env, napi_callback_info info); static napi_value createIdentifierWrapper(napi_env env, napi_callback_info info); static napi_value createExportNamedDeclarationWrapper(napi_env env, napi_callback_info info); static napi_value createImportDeclarationWrapper(napi_env env, napi_callback_info info); + static napi_value createCallExpressionWrapper(napi_env env, napi_callback_info info); + static napi_value createMemberExpressionWrapper(napi_env env, napi_callback_info info); static napi_value createArrayExpressionWrapper(napi_env env, napi_callback_info info); static napi_value createArrowFunctionExpressionWrapper(napi_env env, napi_callback_info info); static napi_value createAssignmentExpressionWrapper(napi_env env, napi_callback_info info); static napi_value createAwaitExpressionWrapper(napi_env env, napi_callback_info info); static napi_value createBinaryExpressionWrapper(napi_env env, napi_callback_info info); - static napi_value createCallExpressionWrapper(napi_env env, napi_callback_info info); + static napi_value createChainExpressionWrapper(napi_env env, napi_callback_info info); static napi_value createClassExpressionWrapper(napi_env env, napi_callback_info info); static napi_value createConditionalExpressionWrapper(napi_env env, napi_callback_info info); static napi_value createFunctionExpressionWrapper(napi_env env, napi_callback_info info); + static napi_value createImportExpressionWrapper(napi_env env, napi_callback_info info); static napi_value createLogicalExpressionWrapper(napi_env env, napi_callback_info info); - static napi_value createMemberExpressionWrapper(napi_env env, napi_callback_info info); static napi_value createMetaPropertyWrapper(napi_env env, napi_callback_info info); static napi_value createNewExpressionWrapper(napi_env env, napi_callback_info info); static napi_value createObjectExpressionWrapper(napi_env env, napi_callback_info info); @@ -156,12 +166,12 @@ class Factory { static napi_value createUnaryExpressionWrapper(napi_env env, napi_callback_info info); static napi_value createUpdateExpressionWrapper(napi_env env, napi_callback_info info); static napi_value createYieldExpressionWrapper(napi_env env, napi_callback_info info); + static napi_value createBigIntLiteralWrapper(napi_env env, napi_callback_info info); static napi_value createBooleanLiteralWrapper(napi_env env, napi_callback_info info); static napi_value createNullLiteralWrapper(napi_env env, napi_callback_info info); static napi_value createNumberLiteralWrapper(napi_env env, napi_callback_info info); static napi_value createRegExpLiteralWrapper(napi_env env, napi_callback_info info); static napi_value createStringLiteralWrapper(napi_env env, napi_callback_info info); - static napi_value createAssignmentPropertyWrapper(napi_env env, napi_callback_info info); static napi_value createArrayPatternWrapper(napi_env env, napi_callback_info info); static napi_value createAssignmentPatternWrapper(napi_env env, napi_callback_info info); static napi_value createObjectPatternWrapper(napi_env env, napi_callback_info info); diff --git a/lib/javascript/addon/addon.cc b/lib/javascript/addon/addon.cc index 4f713b7..afe5f82 100644 --- a/lib/javascript/addon/addon.cc +++ b/lib/javascript/addon/addon.cc @@ -6,6 +6,8 @@ #include "inc/CommentWrapper.h" #include "inc/ModuleDeclarationWrapper.h" #include "inc/VariableDeclaratorWrapper.h" +#include "inc/ChainElementWrapper.h" +#include "inc/PrivateIdentifierWrapper.h" #include "inc/PropertyWrapper.h" #include "inc/SpreadElementWrapper.h" #include "inc/SuperWrapper.h" @@ -15,21 +17,24 @@ #include "inc/SwitchCaseWrapper.h" #include "inc/ClassBodyWrapper.h" #include "inc/MethodDefinitionWrapper.h" +#include "inc/PropertyDefinitionWrapper.h" #include "inc/ProgramWrapper.h" #include "inc/IdentifierWrapper.h" #include "inc/ExportNamedDeclarationWrapper.h" #include "inc/ImportDeclarationWrapper.h" +#include "inc/CallExpressionWrapper.h" +#include "inc/MemberExpressionWrapper.h" #include "inc/ArrayExpressionWrapper.h" #include "inc/ArrowFunctionExpressionWrapper.h" #include "inc/AssignmentExpressionWrapper.h" #include "inc/AwaitExpressionWrapper.h" #include "inc/BinaryExpressionWrapper.h" -#include "inc/CallExpressionWrapper.h" +#include "inc/ChainExpressionWrapper.h" #include "inc/ClassExpressionWrapper.h" #include "inc/ConditionalExpressionWrapper.h" #include "inc/FunctionExpressionWrapper.h" +#include "inc/ImportExpressionWrapper.h" #include "inc/LogicalExpressionWrapper.h" -#include "inc/MemberExpressionWrapper.h" #include "inc/MetaPropertyWrapper.h" #include "inc/NewExpressionWrapper.h" #include "inc/ObjectExpressionWrapper.h" @@ -40,12 +45,12 @@ #include "inc/UnaryExpressionWrapper.h" #include "inc/UpdateExpressionWrapper.h" #include "inc/YieldExpressionWrapper.h" +#include "inc/BigIntLiteralWrapper.h" #include "inc/BooleanLiteralWrapper.h" #include "inc/NullLiteralWrapper.h" #include "inc/NumberLiteralWrapper.h" #include "inc/RegExpLiteralWrapper.h" #include "inc/StringLiteralWrapper.h" -#include "inc/AssignmentPropertyWrapper.h" #include "inc/ArrayPatternWrapper.h" #include "inc/AssignmentPatternWrapper.h" #include "inc/ObjectPatternWrapper.h" @@ -86,6 +91,8 @@ napi_value Init(napi_env env, napi_value exports){ columbus::javascript::asg::addon::CommentWrapper::Init(env, exports); columbus::javascript::asg::addon::ModuleDeclarationWrapper::Init(env, exports); columbus::javascript::asg::addon::VariableDeclaratorWrapper::Init(env, exports); + columbus::javascript::asg::addon::ChainElementWrapper::Init(env, exports); + columbus::javascript::asg::addon::PrivateIdentifierWrapper::Init(env, exports); columbus::javascript::asg::addon::PropertyWrapper::Init(env, exports); columbus::javascript::asg::addon::SpreadElementWrapper::Init(env, exports); columbus::javascript::asg::addon::SuperWrapper::Init(env, exports); @@ -95,21 +102,24 @@ napi_value Init(napi_env env, napi_value exports){ columbus::javascript::asg::addon::SwitchCaseWrapper::Init(env, exports); columbus::javascript::asg::addon::ClassBodyWrapper::Init(env, exports); columbus::javascript::asg::addon::MethodDefinitionWrapper::Init(env, exports); + columbus::javascript::asg::addon::PropertyDefinitionWrapper::Init(env, exports); columbus::javascript::asg::addon::ProgramWrapper::Init(env, exports); columbus::javascript::asg::addon::IdentifierWrapper::Init(env, exports); columbus::javascript::asg::addon::ExportNamedDeclarationWrapper::Init(env, exports); columbus::javascript::asg::addon::ImportDeclarationWrapper::Init(env, exports); + columbus::javascript::asg::addon::CallExpressionWrapper::Init(env, exports); + columbus::javascript::asg::addon::MemberExpressionWrapper::Init(env, exports); columbus::javascript::asg::addon::ArrayExpressionWrapper::Init(env, exports); columbus::javascript::asg::addon::ArrowFunctionExpressionWrapper::Init(env, exports); columbus::javascript::asg::addon::AssignmentExpressionWrapper::Init(env, exports); columbus::javascript::asg::addon::AwaitExpressionWrapper::Init(env, exports); columbus::javascript::asg::addon::BinaryExpressionWrapper::Init(env, exports); - columbus::javascript::asg::addon::CallExpressionWrapper::Init(env, exports); + columbus::javascript::asg::addon::ChainExpressionWrapper::Init(env, exports); columbus::javascript::asg::addon::ClassExpressionWrapper::Init(env, exports); columbus::javascript::asg::addon::ConditionalExpressionWrapper::Init(env, exports); columbus::javascript::asg::addon::FunctionExpressionWrapper::Init(env, exports); + columbus::javascript::asg::addon::ImportExpressionWrapper::Init(env, exports); columbus::javascript::asg::addon::LogicalExpressionWrapper::Init(env, exports); - columbus::javascript::asg::addon::MemberExpressionWrapper::Init(env, exports); columbus::javascript::asg::addon::MetaPropertyWrapper::Init(env, exports); columbus::javascript::asg::addon::NewExpressionWrapper::Init(env, exports); columbus::javascript::asg::addon::ObjectExpressionWrapper::Init(env, exports); @@ -120,12 +130,12 @@ napi_value Init(napi_env env, napi_value exports){ columbus::javascript::asg::addon::UnaryExpressionWrapper::Init(env, exports); columbus::javascript::asg::addon::UpdateExpressionWrapper::Init(env, exports); columbus::javascript::asg::addon::YieldExpressionWrapper::Init(env, exports); + columbus::javascript::asg::addon::BigIntLiteralWrapper::Init(env, exports); columbus::javascript::asg::addon::BooleanLiteralWrapper::Init(env, exports); columbus::javascript::asg::addon::NullLiteralWrapper::Init(env, exports); columbus::javascript::asg::addon::NumberLiteralWrapper::Init(env, exports); columbus::javascript::asg::addon::RegExpLiteralWrapper::Init(env, exports); columbus::javascript::asg::addon::StringLiteralWrapper::Init(env, exports); - columbus::javascript::asg::addon::AssignmentPropertyWrapper::Init(env, exports); columbus::javascript::asg::addon::ArrayPatternWrapper::Init(env, exports); columbus::javascript::asg::addon::AssignmentPatternWrapper::Init(env, exports); columbus::javascript::asg::addon::ObjectPatternWrapper::Init(env, exports); diff --git a/lib/javascript/addon/binding.gyp b/lib/javascript/addon/binding.gyp index 3c4b285..5fd7e10 100644 --- a/lib/javascript/addon/binding.gyp +++ b/lib/javascript/addon/binding.gyp @@ -6,7 +6,7 @@ { 'target_name': 'javascriptAddon', 'sources': [ 'addon.cc', 'Factory.h', 'Factory.cc', - 'inc/SystemWrapper.h' , 'src/SystemWrapper.cc', 'inc/CommentWrapper.h' , 'src/CommentWrapper.cc', 'inc/ModuleDeclarationWrapper.h' , 'src/ModuleDeclarationWrapper.cc', 'inc/VariableDeclaratorWrapper.h' , 'src/VariableDeclaratorWrapper.cc', 'inc/PropertyWrapper.h' , 'src/PropertyWrapper.cc', 'inc/SpreadElementWrapper.h' , 'src/SpreadElementWrapper.cc', 'inc/SuperWrapper.h' , 'src/SuperWrapper.cc', 'inc/TemplateElementWrapper.h' , 'src/TemplateElementWrapper.cc', 'inc/CatchClauseWrapper.h' , 'src/CatchClauseWrapper.cc', 'inc/FunctionWrapper.h' , 'src/FunctionWrapper.cc', 'inc/SwitchCaseWrapper.h' , 'src/SwitchCaseWrapper.cc', 'inc/ClassBodyWrapper.h' , 'src/ClassBodyWrapper.cc', 'inc/MethodDefinitionWrapper.h' , 'src/MethodDefinitionWrapper.cc', 'inc/ProgramWrapper.h' , 'src/ProgramWrapper.cc', 'inc/IdentifierWrapper.h' , 'src/IdentifierWrapper.cc', 'inc/ExportNamedDeclarationWrapper.h' , 'src/ExportNamedDeclarationWrapper.cc', 'inc/ImportDeclarationWrapper.h' , 'src/ImportDeclarationWrapper.cc', 'inc/ArrayExpressionWrapper.h' , 'src/ArrayExpressionWrapper.cc', 'inc/ArrowFunctionExpressionWrapper.h' , 'src/ArrowFunctionExpressionWrapper.cc', 'inc/AssignmentExpressionWrapper.h' , 'src/AssignmentExpressionWrapper.cc', 'inc/AwaitExpressionWrapper.h' , 'src/AwaitExpressionWrapper.cc', 'inc/BinaryExpressionWrapper.h' , 'src/BinaryExpressionWrapper.cc', 'inc/CallExpressionWrapper.h' , 'src/CallExpressionWrapper.cc', 'inc/ClassExpressionWrapper.h' , 'src/ClassExpressionWrapper.cc', 'inc/ConditionalExpressionWrapper.h' , 'src/ConditionalExpressionWrapper.cc', 'inc/FunctionExpressionWrapper.h' , 'src/FunctionExpressionWrapper.cc', 'inc/LogicalExpressionWrapper.h' , 'src/LogicalExpressionWrapper.cc', 'inc/MemberExpressionWrapper.h' , 'src/MemberExpressionWrapper.cc', 'inc/MetaPropertyWrapper.h' , 'src/MetaPropertyWrapper.cc', 'inc/NewExpressionWrapper.h' , 'src/NewExpressionWrapper.cc', 'inc/ObjectExpressionWrapper.h' , 'src/ObjectExpressionWrapper.cc', 'inc/SequenceExpressionWrapper.h' , 'src/SequenceExpressionWrapper.cc', 'inc/TaggedTemplateExpressionWrapper.h' , 'src/TaggedTemplateExpressionWrapper.cc', 'inc/TemplateLiteralWrapper.h' , 'src/TemplateLiteralWrapper.cc', 'inc/ThisExpressionWrapper.h' , 'src/ThisExpressionWrapper.cc', 'inc/UnaryExpressionWrapper.h' , 'src/UnaryExpressionWrapper.cc', 'inc/UpdateExpressionWrapper.h' , 'src/UpdateExpressionWrapper.cc', 'inc/YieldExpressionWrapper.h' , 'src/YieldExpressionWrapper.cc', 'inc/BooleanLiteralWrapper.h' , 'src/BooleanLiteralWrapper.cc', 'inc/NullLiteralWrapper.h' , 'src/NullLiteralWrapper.cc', 'inc/NumberLiteralWrapper.h' , 'src/NumberLiteralWrapper.cc', 'inc/RegExpLiteralWrapper.h' , 'src/RegExpLiteralWrapper.cc', 'inc/StringLiteralWrapper.h' , 'src/StringLiteralWrapper.cc', 'inc/AssignmentPropertyWrapper.h' , 'src/AssignmentPropertyWrapper.cc', 'inc/ArrayPatternWrapper.h' , 'src/ArrayPatternWrapper.cc', 'inc/AssignmentPatternWrapper.h' , 'src/AssignmentPatternWrapper.cc', 'inc/ObjectPatternWrapper.h' , 'src/ObjectPatternWrapper.cc', 'inc/RestElementWrapper.h' , 'src/RestElementWrapper.cc', 'inc/BlockStatementWrapper.h' , 'src/BlockStatementWrapper.cc', 'inc/BreakStatementWrapper.h' , 'src/BreakStatementWrapper.cc', 'inc/ContinueStatementWrapper.h' , 'src/ContinueStatementWrapper.cc', 'inc/DebuggerStatementWrapper.h' , 'src/DebuggerStatementWrapper.cc', 'inc/EmptyStatementWrapper.h' , 'src/EmptyStatementWrapper.cc', 'inc/ExpressionStatementWrapper.h' , 'src/ExpressionStatementWrapper.cc', 'inc/ForInStatementWrapper.h' , 'src/ForInStatementWrapper.cc', 'inc/ForStatementWrapper.h' , 'src/ForStatementWrapper.cc', 'inc/IfStatementWrapper.h' , 'src/IfStatementWrapper.cc', 'inc/LabeledStatementWrapper.h' , 'src/LabeledStatementWrapper.cc', 'inc/ReturnStatementWrapper.h' , 'src/ReturnStatementWrapper.cc', 'inc/SwitchStatementWrapper.h' , 'src/SwitchStatementWrapper.cc', 'inc/ThrowStatementWrapper.h' , 'src/ThrowStatementWrapper.cc', 'inc/TryStatementWrapper.h' , 'src/TryStatementWrapper.cc', 'inc/WhileStatementWrapper.h' , 'src/WhileStatementWrapper.cc', 'inc/WithStatementWrapper.h' , 'src/WithStatementWrapper.cc', 'inc/ClassDeclarationWrapper.h' , 'src/ClassDeclarationWrapper.cc', 'inc/ExportSpecifierWrapper.h' , 'src/ExportSpecifierWrapper.cc', 'inc/FunctionDeclarationWrapper.h' , 'src/FunctionDeclarationWrapper.cc', 'inc/ExportAllDeclarationWrapper.h' , 'src/ExportAllDeclarationWrapper.cc', 'inc/ExportDefaultDeclarationWrapper.h' , 'src/ExportDefaultDeclarationWrapper.cc', 'inc/VariableDeclarationWrapper.h' , 'src/VariableDeclarationWrapper.cc', 'inc/ForOfStatementWrapper.h' , 'src/ForOfStatementWrapper.cc', 'inc/DoWhileStatementWrapper.h' , 'src/DoWhileStatementWrapper.cc', 'inc/ImportDefaultSpecifierWrapper.h' , 'src/ImportDefaultSpecifierWrapper.cc', 'inc/ImportNamespaceSpecifierWrapper.h' , 'src/ImportNamespaceSpecifierWrapper.cc', 'inc/ImportSpecifierWrapper.h' , 'src/ImportSpecifierWrapper.cc', ], + 'inc/SystemWrapper.h' , 'src/SystemWrapper.cc', 'inc/CommentWrapper.h' , 'src/CommentWrapper.cc', 'inc/ModuleDeclarationWrapper.h' , 'src/ModuleDeclarationWrapper.cc', 'inc/VariableDeclaratorWrapper.h' , 'src/VariableDeclaratorWrapper.cc', 'inc/ChainElementWrapper.h' , 'src/ChainElementWrapper.cc', 'inc/PrivateIdentifierWrapper.h' , 'src/PrivateIdentifierWrapper.cc', 'inc/PropertyWrapper.h' , 'src/PropertyWrapper.cc', 'inc/SpreadElementWrapper.h' , 'src/SpreadElementWrapper.cc', 'inc/SuperWrapper.h' , 'src/SuperWrapper.cc', 'inc/TemplateElementWrapper.h' , 'src/TemplateElementWrapper.cc', 'inc/CatchClauseWrapper.h' , 'src/CatchClauseWrapper.cc', 'inc/FunctionWrapper.h' , 'src/FunctionWrapper.cc', 'inc/SwitchCaseWrapper.h' , 'src/SwitchCaseWrapper.cc', 'inc/ClassBodyWrapper.h' , 'src/ClassBodyWrapper.cc', 'inc/MethodDefinitionWrapper.h' , 'src/MethodDefinitionWrapper.cc', 'inc/PropertyDefinitionWrapper.h' , 'src/PropertyDefinitionWrapper.cc', 'inc/ProgramWrapper.h' , 'src/ProgramWrapper.cc', 'inc/IdentifierWrapper.h' , 'src/IdentifierWrapper.cc', 'inc/ExportNamedDeclarationWrapper.h' , 'src/ExportNamedDeclarationWrapper.cc', 'inc/ImportDeclarationWrapper.h' , 'src/ImportDeclarationWrapper.cc', 'inc/CallExpressionWrapper.h' , 'src/CallExpressionWrapper.cc', 'inc/MemberExpressionWrapper.h' , 'src/MemberExpressionWrapper.cc', 'inc/ArrayExpressionWrapper.h' , 'src/ArrayExpressionWrapper.cc', 'inc/ArrowFunctionExpressionWrapper.h' , 'src/ArrowFunctionExpressionWrapper.cc', 'inc/AssignmentExpressionWrapper.h' , 'src/AssignmentExpressionWrapper.cc', 'inc/AwaitExpressionWrapper.h' , 'src/AwaitExpressionWrapper.cc', 'inc/BinaryExpressionWrapper.h' , 'src/BinaryExpressionWrapper.cc', 'inc/ChainExpressionWrapper.h' , 'src/ChainExpressionWrapper.cc', 'inc/ClassExpressionWrapper.h' , 'src/ClassExpressionWrapper.cc', 'inc/ConditionalExpressionWrapper.h' , 'src/ConditionalExpressionWrapper.cc', 'inc/FunctionExpressionWrapper.h' , 'src/FunctionExpressionWrapper.cc', 'inc/ImportExpressionWrapper.h' , 'src/ImportExpressionWrapper.cc', 'inc/LogicalExpressionWrapper.h' , 'src/LogicalExpressionWrapper.cc', 'inc/MetaPropertyWrapper.h' , 'src/MetaPropertyWrapper.cc', 'inc/NewExpressionWrapper.h' , 'src/NewExpressionWrapper.cc', 'inc/ObjectExpressionWrapper.h' , 'src/ObjectExpressionWrapper.cc', 'inc/SequenceExpressionWrapper.h' , 'src/SequenceExpressionWrapper.cc', 'inc/TaggedTemplateExpressionWrapper.h' , 'src/TaggedTemplateExpressionWrapper.cc', 'inc/TemplateLiteralWrapper.h' , 'src/TemplateLiteralWrapper.cc', 'inc/ThisExpressionWrapper.h' , 'src/ThisExpressionWrapper.cc', 'inc/UnaryExpressionWrapper.h' , 'src/UnaryExpressionWrapper.cc', 'inc/UpdateExpressionWrapper.h' , 'src/UpdateExpressionWrapper.cc', 'inc/YieldExpressionWrapper.h' , 'src/YieldExpressionWrapper.cc', 'inc/BigIntLiteralWrapper.h' , 'src/BigIntLiteralWrapper.cc', 'inc/BooleanLiteralWrapper.h' , 'src/BooleanLiteralWrapper.cc', 'inc/NullLiteralWrapper.h' , 'src/NullLiteralWrapper.cc', 'inc/NumberLiteralWrapper.h' , 'src/NumberLiteralWrapper.cc', 'inc/RegExpLiteralWrapper.h' , 'src/RegExpLiteralWrapper.cc', 'inc/StringLiteralWrapper.h' , 'src/StringLiteralWrapper.cc', 'inc/ArrayPatternWrapper.h' , 'src/ArrayPatternWrapper.cc', 'inc/AssignmentPatternWrapper.h' , 'src/AssignmentPatternWrapper.cc', 'inc/ObjectPatternWrapper.h' , 'src/ObjectPatternWrapper.cc', 'inc/RestElementWrapper.h' , 'src/RestElementWrapper.cc', 'inc/BlockStatementWrapper.h' , 'src/BlockStatementWrapper.cc', 'inc/BreakStatementWrapper.h' , 'src/BreakStatementWrapper.cc', 'inc/ContinueStatementWrapper.h' , 'src/ContinueStatementWrapper.cc', 'inc/DebuggerStatementWrapper.h' , 'src/DebuggerStatementWrapper.cc', 'inc/EmptyStatementWrapper.h' , 'src/EmptyStatementWrapper.cc', 'inc/ExpressionStatementWrapper.h' , 'src/ExpressionStatementWrapper.cc', 'inc/ForInStatementWrapper.h' , 'src/ForInStatementWrapper.cc', 'inc/ForStatementWrapper.h' , 'src/ForStatementWrapper.cc', 'inc/IfStatementWrapper.h' , 'src/IfStatementWrapper.cc', 'inc/LabeledStatementWrapper.h' , 'src/LabeledStatementWrapper.cc', 'inc/ReturnStatementWrapper.h' , 'src/ReturnStatementWrapper.cc', 'inc/SwitchStatementWrapper.h' , 'src/SwitchStatementWrapper.cc', 'inc/ThrowStatementWrapper.h' , 'src/ThrowStatementWrapper.cc', 'inc/TryStatementWrapper.h' , 'src/TryStatementWrapper.cc', 'inc/WhileStatementWrapper.h' , 'src/WhileStatementWrapper.cc', 'inc/WithStatementWrapper.h' , 'src/WithStatementWrapper.cc', 'inc/ClassDeclarationWrapper.h' , 'src/ClassDeclarationWrapper.cc', 'inc/ExportSpecifierWrapper.h' , 'src/ExportSpecifierWrapper.cc', 'inc/FunctionDeclarationWrapper.h' , 'src/FunctionDeclarationWrapper.cc', 'inc/ExportAllDeclarationWrapper.h' , 'src/ExportAllDeclarationWrapper.cc', 'inc/ExportDefaultDeclarationWrapper.h' , 'src/ExportDefaultDeclarationWrapper.cc', 'inc/VariableDeclarationWrapper.h' , 'src/VariableDeclarationWrapper.cc', 'inc/ForOfStatementWrapper.h' , 'src/ForOfStatementWrapper.cc', 'inc/DoWhileStatementWrapper.h' , 'src/DoWhileStatementWrapper.cc', 'inc/ImportDefaultSpecifierWrapper.h' , 'src/ImportDefaultSpecifierWrapper.cc', 'inc/ImportNamespaceSpecifierWrapper.h' , 'src/ImportNamespaceSpecifierWrapper.cc', 'inc/ImportSpecifierWrapper.h' , 'src/ImportSpecifierWrapper.cc', ], 'include_dirs': [ '../../', '<(source_dir)/inc', @@ -16,7 +16,7 @@ 'conditions': [ ['OS=="linux"', { "cflags_cc!": [ "-fno-rtti" ], - "cflags_cc": [ "-fPIC", "-isystem <(bin_dir)/3rdparty/install/include" ], + "cflags_cc": [ "-fexceptions", "-fPIC", "-isystem <(bin_dir)/3rdparty/install/include" ], }], ['OS=="win"', { diff --git a/lib/javascript/addon/inc/BigIntLiteralWrapper.h b/lib/javascript/addon/inc/BigIntLiteralWrapper.h new file mode 100644 index 0000000..c3aa746 --- /dev/null +++ b/lib/javascript/addon/inc/BigIntLiteralWrapper.h @@ -0,0 +1,52 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _JAVASCRIPT_BigIntLiteralWrapper_H_ +#define _JAVASCRIPT_BigIntLiteralWrapper_H_ + +#include "javascript/inc/javascript.h" +#include +#include "BaseWrapper.h" +#include "../Factory.h" + +namespace columbus { namespace javascript { namespace asg { namespace addon { + class Factory; + + class BigIntLiteralWrapper : BaseWrapper{ + public: + static napi_value Init(napi_env env, napi_value& exports); + static void Destructor(napi_env env, void* nativeObject, void* finalize_hint); + static napi_status NewInstance(napi_env env, expression::BigIntLiteral* arg, napi_value* instance); + private: + explicit BigIntLiteralWrapper(); // Constructor + ~BigIntLiteralWrapper(); + static napi_ref constructor; + static napi_value New(napi_env env, napi_callback_info info); + napi_env env_; + napi_ref wrapper_; + static napi_value addComments(napi_env env, napi_callback_info info); + static napi_value setBigint(napi_env env, napi_callback_info info); + static napi_value setPath(napi_env env, napi_callback_info info); + static napi_value setPosition(napi_env env, napi_callback_info info); + static napi_value setRaw(napi_env env, napi_callback_info info); + }; //end of BigIntLiteralWrapper + +}}}}//end of namespaces +#endif \ No newline at end of file diff --git a/lib/javascript/addon/inc/CallExpressionWrapper.h b/lib/javascript/addon/inc/CallExpressionWrapper.h index e3a5f4b..fe0cdc1 100644 --- a/lib/javascript/addon/inc/CallExpressionWrapper.h +++ b/lib/javascript/addon/inc/CallExpressionWrapper.h @@ -47,6 +47,7 @@ namespace columbus { namespace javascript { namespace asg { namespace addon { static napi_value addComments(napi_env env, napi_callback_info info); static napi_value setPath(napi_env env, napi_callback_info info); static napi_value setPosition(napi_env env, napi_callback_info info); + static napi_value setOptional(napi_env env, napi_callback_info info); }; //end of CallExpressionWrapper }}}}//end of namespaces diff --git a/lib/javascript/addon/inc/ChainElementWrapper.h b/lib/javascript/addon/inc/ChainElementWrapper.h new file mode 100644 index 0000000..28a4226 --- /dev/null +++ b/lib/javascript/addon/inc/ChainElementWrapper.h @@ -0,0 +1,51 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _JAVASCRIPT_ChainElementWrapper_H_ +#define _JAVASCRIPT_ChainElementWrapper_H_ + +#include "javascript/inc/javascript.h" +#include +#include "BaseWrapper.h" +#include "../Factory.h" + +namespace columbus { namespace javascript { namespace asg { namespace addon { + class Factory; + + class ChainElementWrapper : BaseWrapper{ + public: + static napi_value Init(napi_env env, napi_value& exports); + static void Destructor(napi_env env, void* nativeObject, void* finalize_hint); + static napi_status NewInstance(napi_env env, expression::ChainElement* arg, napi_value* instance); + private: + explicit ChainElementWrapper(); // Constructor + ~ChainElementWrapper(); + static napi_ref constructor; + static napi_value New(napi_env env, napi_callback_info info); + napi_env env_; + napi_ref wrapper_; + static napi_value addComments(napi_env env, napi_callback_info info); + static napi_value setOptional(napi_env env, napi_callback_info info); + static napi_value setPath(napi_env env, napi_callback_info info); + static napi_value setPosition(napi_env env, napi_callback_info info); + }; //end of ChainElementWrapper + +}}}}//end of namespaces +#endif \ No newline at end of file diff --git a/lib/javascript/addon/inc/ChainExpressionWrapper.h b/lib/javascript/addon/inc/ChainExpressionWrapper.h new file mode 100644 index 0000000..ffe7c3d --- /dev/null +++ b/lib/javascript/addon/inc/ChainExpressionWrapper.h @@ -0,0 +1,51 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _JAVASCRIPT_ChainExpressionWrapper_H_ +#define _JAVASCRIPT_ChainExpressionWrapper_H_ + +#include "javascript/inc/javascript.h" +#include +#include "BaseWrapper.h" +#include "../Factory.h" + +namespace columbus { namespace javascript { namespace asg { namespace addon { + class Factory; + + class ChainExpressionWrapper : BaseWrapper{ + public: + static napi_value Init(napi_env env, napi_value& exports); + static void Destructor(napi_env env, void* nativeObject, void* finalize_hint); + static napi_status NewInstance(napi_env env, expression::ChainExpression* arg, napi_value* instance); + private: + explicit ChainExpressionWrapper(); // Constructor + ~ChainExpressionWrapper(); + static napi_ref constructor; + static napi_value New(napi_env env, napi_callback_info info); + napi_env env_; + napi_ref wrapper_; + static napi_value setExpression(napi_env env, napi_callback_info info); + static napi_value addComments(napi_env env, napi_callback_info info); + static napi_value setPath(napi_env env, napi_callback_info info); + static napi_value setPosition(napi_env env, napi_callback_info info); + }; //end of ChainExpressionWrapper + +}}}}//end of namespaces +#endif \ No newline at end of file diff --git a/lib/javascript/addon/inc/ExportAllDeclarationWrapper.h b/lib/javascript/addon/inc/ExportAllDeclarationWrapper.h index 89cae20..bb0f369 100644 --- a/lib/javascript/addon/inc/ExportAllDeclarationWrapper.h +++ b/lib/javascript/addon/inc/ExportAllDeclarationWrapper.h @@ -42,6 +42,7 @@ namespace columbus { namespace javascript { namespace asg { namespace addon { napi_env env_; napi_ref wrapper_; static napi_value setSource(napi_env env, napi_callback_info info); + static napi_value setExported(napi_env env, napi_callback_info info); static napi_value addComments(napi_env env, napi_callback_info info); static napi_value setPath(napi_env env, napi_callback_info info); static napi_value setPosition(napi_env env, napi_callback_info info); diff --git a/lib/javascript/addon/inc/ForOfStatementWrapper.h b/lib/javascript/addon/inc/ForOfStatementWrapper.h index 1262e29..0160dba 100644 --- a/lib/javascript/addon/inc/ForOfStatementWrapper.h +++ b/lib/javascript/addon/inc/ForOfStatementWrapper.h @@ -45,7 +45,7 @@ namespace columbus { namespace javascript { namespace asg { namespace addon { static napi_value setBody(napi_env env, napi_callback_info info); static napi_value setLeft(napi_env env, napi_callback_info info); static napi_value addComments(napi_env env, napi_callback_info info); - static napi_value setAsync(napi_env env, napi_callback_info info); + static napi_value setAwait(napi_env env, napi_callback_info info); static napi_value setPath(napi_env env, napi_callback_info info); static napi_value setPosition(napi_env env, napi_callback_info info); }; //end of ForOfStatementWrapper diff --git a/lib/javascript/addon/inc/ImportExpressionWrapper.h b/lib/javascript/addon/inc/ImportExpressionWrapper.h new file mode 100644 index 0000000..87e1426 --- /dev/null +++ b/lib/javascript/addon/inc/ImportExpressionWrapper.h @@ -0,0 +1,51 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _JAVASCRIPT_ImportExpressionWrapper_H_ +#define _JAVASCRIPT_ImportExpressionWrapper_H_ + +#include "javascript/inc/javascript.h" +#include +#include "BaseWrapper.h" +#include "../Factory.h" + +namespace columbus { namespace javascript { namespace asg { namespace addon { + class Factory; + + class ImportExpressionWrapper : BaseWrapper{ + public: + static napi_value Init(napi_env env, napi_value& exports); + static void Destructor(napi_env env, void* nativeObject, void* finalize_hint); + static napi_status NewInstance(napi_env env, expression::ImportExpression* arg, napi_value* instance); + private: + explicit ImportExpressionWrapper(); // Constructor + ~ImportExpressionWrapper(); + static napi_ref constructor; + static napi_value New(napi_env env, napi_callback_info info); + napi_env env_; + napi_ref wrapper_; + static napi_value setSource(napi_env env, napi_callback_info info); + static napi_value addComments(napi_env env, napi_callback_info info); + static napi_value setPath(napi_env env, napi_callback_info info); + static napi_value setPosition(napi_env env, napi_callback_info info); + }; //end of ImportExpressionWrapper + +}}}}//end of namespaces +#endif \ No newline at end of file diff --git a/lib/javascript/addon/inc/MemberExpressionWrapper.h b/lib/javascript/addon/inc/MemberExpressionWrapper.h index aa610f1..d0f5019 100644 --- a/lib/javascript/addon/inc/MemberExpressionWrapper.h +++ b/lib/javascript/addon/inc/MemberExpressionWrapper.h @@ -47,6 +47,7 @@ namespace columbus { namespace javascript { namespace asg { namespace addon { static napi_value setComputed(napi_env env, napi_callback_info info); static napi_value setPath(napi_env env, napi_callback_info info); static napi_value setPosition(napi_env env, napi_callback_info info); + static napi_value setOptional(napi_env env, napi_callback_info info); }; //end of MemberExpressionWrapper }}}}//end of namespaces diff --git a/lib/javascript/addon/inc/PrivateIdentifierWrapper.h b/lib/javascript/addon/inc/PrivateIdentifierWrapper.h new file mode 100644 index 0000000..1ea7ae5 --- /dev/null +++ b/lib/javascript/addon/inc/PrivateIdentifierWrapper.h @@ -0,0 +1,51 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _JAVASCRIPT_PrivateIdentifierWrapper_H_ +#define _JAVASCRIPT_PrivateIdentifierWrapper_H_ + +#include "javascript/inc/javascript.h" +#include +#include "BaseWrapper.h" +#include "../Factory.h" + +namespace columbus { namespace javascript { namespace asg { namespace addon { + class Factory; + + class PrivateIdentifierWrapper : BaseWrapper{ + public: + static napi_value Init(napi_env env, napi_value& exports); + static void Destructor(napi_env env, void* nativeObject, void* finalize_hint); + static napi_status NewInstance(napi_env env, expression::PrivateIdentifier* arg, napi_value* instance); + private: + explicit PrivateIdentifierWrapper(); // Constructor + ~PrivateIdentifierWrapper(); + static napi_ref constructor; + static napi_value New(napi_env env, napi_callback_info info); + napi_env env_; + napi_ref wrapper_; + static napi_value addComments(napi_env env, napi_callback_info info); + static napi_value setPath(napi_env env, napi_callback_info info); + static napi_value setPosition(napi_env env, napi_callback_info info); + static napi_value setName(napi_env env, napi_callback_info info); + }; //end of PrivateIdentifierWrapper + +}}}}//end of namespaces +#endif \ No newline at end of file diff --git a/lib/javascript/addon/inc/AssignmentPropertyWrapper.h b/lib/javascript/addon/inc/PropertyDefinitionWrapper.h similarity index 74% rename from lib/javascript/addon/inc/AssignmentPropertyWrapper.h rename to lib/javascript/addon/inc/PropertyDefinitionWrapper.h index 925da8e..74104e9 100644 --- a/lib/javascript/addon/inc/AssignmentPropertyWrapper.h +++ b/lib/javascript/addon/inc/PropertyDefinitionWrapper.h @@ -18,8 +18,8 @@ * limitations under the Licence. */ -#ifndef _JAVASCRIPT_AssignmentPropertyWrapper_H_ -#define _JAVASCRIPT_AssignmentPropertyWrapper_H_ +#ifndef _JAVASCRIPT_PropertyDefinitionWrapper_H_ +#define _JAVASCRIPT_PropertyDefinitionWrapper_H_ #include "javascript/inc/javascript.h" #include @@ -29,28 +29,26 @@ namespace columbus { namespace javascript { namespace asg { namespace addon { class Factory; - class AssignmentPropertyWrapper : BaseWrapper{ + class PropertyDefinitionWrapper : BaseWrapper{ public: static napi_value Init(napi_env env, napi_value& exports); static void Destructor(napi_env env, void* nativeObject, void* finalize_hint); - static napi_status NewInstance(napi_env env, expression::AssignmentProperty* arg, napi_value* instance); + static napi_status NewInstance(napi_env env, structure::PropertyDefinition* arg, napi_value* instance); private: - explicit AssignmentPropertyWrapper(); // Constructor - ~AssignmentPropertyWrapper(); + explicit PropertyDefinitionWrapper(); // Constructor + ~PropertyDefinitionWrapper(); static napi_ref constructor; static napi_value New(napi_env env, napi_callback_info info); napi_env env_; napi_ref wrapper_; - static napi_value setValue(napi_env env, napi_callback_info info); static napi_value setKey(napi_env env, napi_callback_info info); + static napi_value setValue(napi_env env, napi_callback_info info); static napi_value addComments(napi_env env, napi_callback_info info); - static napi_value setKind(napi_env env, napi_callback_info info); - static napi_value setMethod(napi_env env, napi_callback_info info); - static napi_value setShorthand(napi_env env, napi_callback_info info); static napi_value setComputed(napi_env env, napi_callback_info info); + static napi_value setStatic(napi_env env, napi_callback_info info); static napi_value setPath(napi_env env, napi_callback_info info); static napi_value setPosition(napi_env env, napi_callback_info info); - }; //end of AssignmentPropertyWrapper + }; //end of PropertyDefinitionWrapper }}}}//end of namespaces #endif \ No newline at end of file diff --git a/lib/javascript/addon/src/AssignmentExpressionWrapper.cc b/lib/javascript/addon/src/AssignmentExpressionWrapper.cc index 1e6dcfa..0d42670 100644 --- a/lib/javascript/addon/src/AssignmentExpressionWrapper.cc +++ b/lib/javascript/addon/src/AssignmentExpressionWrapper.cc @@ -240,6 +240,15 @@ napi_value AssignmentExpressionWrapper::setOperator(napi_env env, napi_callback_ if( param == "asoExponentiation" ){ dynamic_cast(obj->_nativeObj)->setOperator( asoExponentiation ); } + if( param == "asoAnd" ){ + dynamic_cast(obj->_nativeObj)->setOperator( asoAnd ); + } + if( param == "asoOr" ){ + dynamic_cast(obj->_nativeObj)->setOperator( asoOr ); + } + if( param == "asoNullishCoalescing" ){ + dynamic_cast(obj->_nativeObj)->setOperator( asoNullishCoalescing ); + } return nullptr; } napi_value AssignmentExpressionWrapper::setPath(napi_env env, napi_callback_info info) { diff --git a/lib/javascript/addon/src/BigIntLiteralWrapper.cc b/lib/javascript/addon/src/BigIntLiteralWrapper.cc new file mode 100644 index 0000000..6e45b86 --- /dev/null +++ b/lib/javascript/addon/src/BigIntLiteralWrapper.cc @@ -0,0 +1,303 @@ +#include "../inc/BigIntLiteralWrapper.h" +#include +namespace columbus { namespace javascript { namespace asg { namespace addon { + +napi_ref BigIntLiteralWrapper::constructor; + +BigIntLiteralWrapper::BigIntLiteralWrapper(): env_(nullptr), wrapper_(nullptr) {} + +BigIntLiteralWrapper::~BigIntLiteralWrapper(){ napi_delete_reference(env_, wrapper_); } + +void BigIntLiteralWrapper::Destructor(napi_env env, void* nativeObject, void* ){ + BigIntLiteralWrapper* obj = reinterpret_cast(nativeObject); + //delete obj->_nativeObj; + obj->~BigIntLiteralWrapper(); +} +napi_value BigIntLiteralWrapper::Init(napi_env env, napi_value& exports) { + napi_status status; + napi_property_descriptor props [] = { + DECLARE_NAPI_METHOD( "addComments", addComments), + DECLARE_NAPI_METHOD("setBigint", setBigint), + DECLARE_NAPI_METHOD("setPath", setPath), + DECLARE_NAPI_METHOD("setPosition", setPosition), + DECLARE_NAPI_METHOD("setRaw", setRaw), + }; + + napi_value cons; + status = napi_define_class(env, "BigIntLiteralWrapper", NAPI_AUTO_LENGTH, New, nullptr, sizeof(props) / sizeof(*props), props, &cons ); + assert(status == napi_ok); + + status = napi_create_reference(env, cons, 1, &constructor); + assert(status == napi_ok); + + return exports; +} +napi_value BigIntLiteralWrapper::New(napi_env env, napi_callback_info info) { + napi_status status; + napi_value jsthis; + + status = napi_get_cb_info(env, info, 0, nullptr, &jsthis, nullptr); + assert(status == napi_ok); + + BigIntLiteralWrapper* obj = new BigIntLiteralWrapper(); + obj->env_ = env; + status = napi_wrap(env, jsthis, reinterpret_cast(obj), BigIntLiteralWrapper::Destructor, nullptr, &obj->wrapper_); + assert(status == napi_ok); + + return jsthis; +} + + +napi_status BigIntLiteralWrapper::NewInstance(napi_env env, expression::BigIntLiteral* arg, napi_value* instance) { + + napi_status status; + napi_value cons; + + status = napi_get_reference_value(env, constructor, &cons); + if(status != napi_ok) return status; + + status = napi_new_instance(env, cons, 0, nullptr, instance); + if(status != napi_ok) return status; + + BigIntLiteralWrapper* obj; + status = napi_unwrap(env, *instance, reinterpret_cast(&obj)); + obj->_nativeObj = arg; + return napi_ok; +} + +napi_value BigIntLiteralWrapper::addComments(napi_env env, napi_callback_info info){ + napi_status status; + napi_value jsthis; + size_t argc = 1; + napi_value args[1]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments."); + return nullptr; + } + + BigIntLiteralWrapper* obj; + BaseWrapper* param; + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + status = napi_unwrap(env, args[0], reinterpret_cast(¶m)); + assert(status == napi_ok); + + columbus::javascript::asg::expression::BigIntLiteral* source = dynamic_cast(obj->_nativeObj); + columbus::javascript::asg::base::Comment* target = dynamic_cast(param->_nativeObj); + + if(source == nullptr){ + status = napi_throw_error(env, nullptr, "Cannot cast expression::BigIntLiteral" ); + } + if(target == nullptr){ + status = napi_throw_error(env, nullptr, "Cannot cast base::Comment" ); + } + + source->addComments(target); + return nullptr; +} +napi_value BigIntLiteralWrapper::setBigint(napi_env env, napi_callback_info info){ + napi_status status; + napi_value jsthis; + size_t argc = 1; + napi_value args[1]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments."); + return nullptr; + } + + BigIntLiteralWrapper* obj; + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + napi_valuetype paramtype; + status = napi_typeof(env, args[0], ¶mtype); + assert(status == napi_ok); + + if(paramtype != napi_string && paramtype != napi_null){ + napi_throw_type_error(env, nullptr, "Argument should be a string!"); + return nullptr; + } + + if(paramtype == napi_null){ + dynamic_cast(obj->_nativeObj)->setBigint( std::string("null") ); + } + else{ + char buffer[1024]; + size_t buffer_size = 1024, result_size = 0; + status = napi_get_value_string_utf8(env, args[0], buffer, buffer_size, &result_size); + assert(status == napi_ok); + + std::string param(buffer); + dynamic_cast(obj->_nativeObj)->setBigint( param ); + } + return nullptr; +} +napi_value BigIntLiteralWrapper::setPath(napi_env env, napi_callback_info info) { + napi_status status; + napi_value jsthis; + size_t argc = 1; + napi_value args[1]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments"); + return nullptr; + } + + BigIntLiteralWrapper* obj; + napi_valuetype valuetype; + status = napi_typeof(env, args[0], &valuetype); + assert(status == napi_ok); + + if (valuetype != napi_string) { + napi_throw_type_error(env, nullptr, "Argument should be a string!"); + return nullptr; + } + + char buffer[1024]; + size_t buffer_size = 1024, result_size = 0; + status = napi_get_value_string_utf8(env, args[0], buffer, buffer_size, &result_size); + assert(status == napi_ok); + + std::string path(buffer); + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + Range range = dynamic_cast(obj->_nativeObj)->getPosition(); + range.setPath( path ); + dynamic_cast(obj->_nativeObj)->setPosition( range ); + return nullptr; +} + + +napi_value BigIntLiteralWrapper::setPosition(napi_env env, napi_callback_info info) { + napi_status status; + napi_value jsthis; + size_t argc = 8; + napi_value args[8]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1 && argc != 8) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments. Use a simple object with the positions or pass 8 parameters: line, col, endline, endcol and their wide equivalents!"); + return nullptr; + } + + BigIntLiteralWrapper* obj; + napi_valuetype valuetype[8]; + int32_t position[8]; + bool hasProp[8]; + if(argc == 1){ + status = napi_typeof(env, args[0], &valuetype[0]); + assert(status == napi_ok); + + if(valuetype[0] != napi_object){ + napi_throw_type_error(env, nullptr, "Argument should be an object!"); + return nullptr; + } + + std::string props[] = {"line", "col", "endline", "endcol", "wideline", "widecol", "wideendline", "wideendcol",}; + + for(int i = 0; i < 8; ++i){ + status = napi_has_named_property(env, args[0], props[i].c_str(), &hasProp[i]); + assert(status == napi_ok); + napi_value value; + if(hasProp[i]){ + status = napi_get_named_property(env, args[0], props[i].c_str(), &value); + assert(status == napi_ok); + status = napi_get_value_int32(env, value, &position[i]); + assert(status == napi_ok); + } + + } + } + else{ + for(int i = 0; i < 8; ++i){ + status = napi_typeof(env, args[i], &valuetype[i]); + assert(status == napi_ok); + if(valuetype[i] != napi_number){ + napi_throw_type_error(env, nullptr, "Argument should be an integer!"); + return nullptr; + } + status = napi_get_value_int32(env, args[i], &position[i]); + assert(status == napi_ok); + } + for(int i = 0; i < 8; ++i){ + hasProp[i] = true; + } + } + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + Range range = dynamic_cast(obj->_nativeObj)->getPosition(); + + if(hasProp[0]) + range.setLine( (int)position[0] ); + if(hasProp[1]) + range.setCol( (int)position[1] ); + if(hasProp[2]) + range.setEndLine( (int)position[2] ); + if(hasProp[3]) + range.setEndCol( (int)position[3] ); + if(hasProp[4]) + range.setWideLine( (int)position[4] ); + if(hasProp[5]) + range.setWideCol( (int)position[5] ); + if(hasProp[6]) + range.setWideEndLine( (int)position[6] ); + if(hasProp[7]) + range.setWideEndCol( (int)position[7] ); + dynamic_cast(obj->_nativeObj)->setPosition( range ); + return nullptr; +} + + +napi_value BigIntLiteralWrapper::setRaw(napi_env env, napi_callback_info info){ + napi_status status; + napi_value jsthis; + size_t argc = 1; + napi_value args[1]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments."); + return nullptr; + } + + BigIntLiteralWrapper* obj; + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + napi_valuetype paramtype; + status = napi_typeof(env, args[0], ¶mtype); + assert(status == napi_ok); + + if(paramtype != napi_string && paramtype != napi_null){ + napi_throw_type_error(env, nullptr, "Argument should be a string!"); + return nullptr; + } + + if(paramtype == napi_null){ + dynamic_cast(obj->_nativeObj)->setRaw( std::string("null") ); + } + else{ + char buffer[1024]; + size_t buffer_size = 1024, result_size = 0; + status = napi_get_value_string_utf8(env, args[0], buffer, buffer_size, &result_size); + assert(status == napi_ok); + + std::string param(buffer); + dynamic_cast(obj->_nativeObj)->setRaw( param ); + } + return nullptr; +} +}}}} //end of namespaces \ No newline at end of file diff --git a/lib/javascript/addon/src/BinaryExpressionWrapper.cc b/lib/javascript/addon/src/BinaryExpressionWrapper.cc index 8a438a4..5e0dced 100644 --- a/lib/javascript/addon/src/BinaryExpressionWrapper.cc +++ b/lib/javascript/addon/src/BinaryExpressionWrapper.cc @@ -88,13 +88,13 @@ napi_value BinaryExpressionWrapper::setLeft(napi_env env, napi_callback_info inf assert(status == napi_ok); columbus::javascript::asg::expression::BinaryExpression* source = dynamic_cast(obj->_nativeObj); - columbus::javascript::asg::expression::Expression* target = dynamic_cast(param->_nativeObj); + columbus::javascript::asg::base::Positioned* target = dynamic_cast(param->_nativeObj); if(source == nullptr){ status = napi_throw_error(env, nullptr, "Cannot cast expression::BinaryExpression" ); } if(target == nullptr){ - status = napi_throw_error(env, nullptr, "Cannot cast expression::Expression" ); + status = napi_throw_error(env, nullptr, "Cannot cast base::Positioned" ); } source->setLeft(target); diff --git a/lib/javascript/addon/src/CallExpressionWrapper.cc b/lib/javascript/addon/src/CallExpressionWrapper.cc index 92fee95..992c570 100644 --- a/lib/javascript/addon/src/CallExpressionWrapper.cc +++ b/lib/javascript/addon/src/CallExpressionWrapper.cc @@ -22,6 +22,7 @@ napi_value CallExpressionWrapper::Init(napi_env env, napi_value& exports) { DECLARE_NAPI_METHOD( "addComments", addComments), DECLARE_NAPI_METHOD("setPath", setPath), DECLARE_NAPI_METHOD("setPosition", setPosition), + DECLARE_NAPI_METHOD("setOptional", setOptional), }; napi_value cons; @@ -323,4 +324,36 @@ napi_value CallExpressionWrapper::setPosition(napi_env env, napi_callback_info i } +napi_value CallExpressionWrapper::setOptional(napi_env env, napi_callback_info info){ + napi_status status; + napi_value jsthis; + size_t argc = 1; + napi_value args[1]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments."); + return nullptr; + } + + CallExpressionWrapper* obj; + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + napi_valuetype paramtype; + status = napi_typeof(env, args[0], ¶mtype); + assert(status == napi_ok); + + if(paramtype != napi_boolean){ + napi_throw_type_error(env, nullptr, "Argument should be a boolean!"); + return nullptr; + } + + bool b; + status = napi_get_value_bool(env, args[0], &b); + assert(status == napi_ok); + dynamic_cast(obj->_nativeObj)->setOptional( b ); + return nullptr; +} }}}} //end of namespaces \ No newline at end of file diff --git a/lib/javascript/addon/src/ChainElementWrapper.cc b/lib/javascript/addon/src/ChainElementWrapper.cc new file mode 100644 index 0000000..adca0bf --- /dev/null +++ b/lib/javascript/addon/src/ChainElementWrapper.cc @@ -0,0 +1,254 @@ +#include "../inc/ChainElementWrapper.h" +#include +namespace columbus { namespace javascript { namespace asg { namespace addon { + +napi_ref ChainElementWrapper::constructor; + +ChainElementWrapper::ChainElementWrapper(): env_(nullptr), wrapper_(nullptr) {} + +ChainElementWrapper::~ChainElementWrapper(){ napi_delete_reference(env_, wrapper_); } + +void ChainElementWrapper::Destructor(napi_env env, void* nativeObject, void* ){ + ChainElementWrapper* obj = reinterpret_cast(nativeObject); + //delete obj->_nativeObj; + obj->~ChainElementWrapper(); +} +napi_value ChainElementWrapper::Init(napi_env env, napi_value& exports) { + napi_status status; + napi_property_descriptor props [] = { + DECLARE_NAPI_METHOD( "addComments", addComments), + DECLARE_NAPI_METHOD("setOptional", setOptional), + DECLARE_NAPI_METHOD("setPath", setPath), + DECLARE_NAPI_METHOD("setPosition", setPosition), + }; + + napi_value cons; + status = napi_define_class(env, "ChainElementWrapper", NAPI_AUTO_LENGTH, New, nullptr, sizeof(props) / sizeof(*props), props, &cons ); + assert(status == napi_ok); + + status = napi_create_reference(env, cons, 1, &constructor); + assert(status == napi_ok); + + return exports; +} +napi_value ChainElementWrapper::New(napi_env env, napi_callback_info info) { + napi_status status; + napi_value jsthis; + + status = napi_get_cb_info(env, info, 0, nullptr, &jsthis, nullptr); + assert(status == napi_ok); + + ChainElementWrapper* obj = new ChainElementWrapper(); + obj->env_ = env; + status = napi_wrap(env, jsthis, reinterpret_cast(obj), ChainElementWrapper::Destructor, nullptr, &obj->wrapper_); + assert(status == napi_ok); + + return jsthis; +} + + +napi_status ChainElementWrapper::NewInstance(napi_env env, expression::ChainElement* arg, napi_value* instance) { + + napi_status status; + napi_value cons; + + status = napi_get_reference_value(env, constructor, &cons); + if(status != napi_ok) return status; + + status = napi_new_instance(env, cons, 0, nullptr, instance); + if(status != napi_ok) return status; + + ChainElementWrapper* obj; + status = napi_unwrap(env, *instance, reinterpret_cast(&obj)); + obj->_nativeObj = arg; + return napi_ok; +} + +napi_value ChainElementWrapper::addComments(napi_env env, napi_callback_info info){ + napi_status status; + napi_value jsthis; + size_t argc = 1; + napi_value args[1]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments."); + return nullptr; + } + + ChainElementWrapper* obj; + BaseWrapper* param; + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + status = napi_unwrap(env, args[0], reinterpret_cast(¶m)); + assert(status == napi_ok); + + columbus::javascript::asg::expression::ChainElement* source = dynamic_cast(obj->_nativeObj); + columbus::javascript::asg::base::Comment* target = dynamic_cast(param->_nativeObj); + + if(source == nullptr){ + status = napi_throw_error(env, nullptr, "Cannot cast expression::ChainElement" ); + } + if(target == nullptr){ + status = napi_throw_error(env, nullptr, "Cannot cast base::Comment" ); + } + + source->addComments(target); + return nullptr; +} +napi_value ChainElementWrapper::setOptional(napi_env env, napi_callback_info info){ + napi_status status; + napi_value jsthis; + size_t argc = 1; + napi_value args[1]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments."); + return nullptr; + } + + ChainElementWrapper* obj; + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + napi_valuetype paramtype; + status = napi_typeof(env, args[0], ¶mtype); + assert(status == napi_ok); + + if(paramtype != napi_boolean){ + napi_throw_type_error(env, nullptr, "Argument should be a boolean!"); + return nullptr; + } + + bool b; + status = napi_get_value_bool(env, args[0], &b); + assert(status == napi_ok); + dynamic_cast(obj->_nativeObj)->setOptional( b ); + return nullptr; +} +napi_value ChainElementWrapper::setPath(napi_env env, napi_callback_info info) { + napi_status status; + napi_value jsthis; + size_t argc = 1; + napi_value args[1]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments"); + return nullptr; + } + + ChainElementWrapper* obj; + napi_valuetype valuetype; + status = napi_typeof(env, args[0], &valuetype); + assert(status == napi_ok); + + if (valuetype != napi_string) { + napi_throw_type_error(env, nullptr, "Argument should be a string!"); + return nullptr; + } + + char buffer[1024]; + size_t buffer_size = 1024, result_size = 0; + status = napi_get_value_string_utf8(env, args[0], buffer, buffer_size, &result_size); + assert(status == napi_ok); + + std::string path(buffer); + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + Range range = dynamic_cast(obj->_nativeObj)->getPosition(); + range.setPath( path ); + dynamic_cast(obj->_nativeObj)->setPosition( range ); + return nullptr; +} + + +napi_value ChainElementWrapper::setPosition(napi_env env, napi_callback_info info) { + napi_status status; + napi_value jsthis; + size_t argc = 8; + napi_value args[8]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1 && argc != 8) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments. Use a simple object with the positions or pass 8 parameters: line, col, endline, endcol and their wide equivalents!"); + return nullptr; + } + + ChainElementWrapper* obj; + napi_valuetype valuetype[8]; + int32_t position[8]; + bool hasProp[8]; + if(argc == 1){ + status = napi_typeof(env, args[0], &valuetype[0]); + assert(status == napi_ok); + + if(valuetype[0] != napi_object){ + napi_throw_type_error(env, nullptr, "Argument should be an object!"); + return nullptr; + } + + std::string props[] = {"line", "col", "endline", "endcol", "wideline", "widecol", "wideendline", "wideendcol",}; + + for(int i = 0; i < 8; ++i){ + status = napi_has_named_property(env, args[0], props[i].c_str(), &hasProp[i]); + assert(status == napi_ok); + napi_value value; + if(hasProp[i]){ + status = napi_get_named_property(env, args[0], props[i].c_str(), &value); + assert(status == napi_ok); + status = napi_get_value_int32(env, value, &position[i]); + assert(status == napi_ok); + } + + } + } + else{ + for(int i = 0; i < 8; ++i){ + status = napi_typeof(env, args[i], &valuetype[i]); + assert(status == napi_ok); + if(valuetype[i] != napi_number){ + napi_throw_type_error(env, nullptr, "Argument should be an integer!"); + return nullptr; + } + status = napi_get_value_int32(env, args[i], &position[i]); + assert(status == napi_ok); + } + for(int i = 0; i < 8; ++i){ + hasProp[i] = true; + } + } + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + Range range = dynamic_cast(obj->_nativeObj)->getPosition(); + + if(hasProp[0]) + range.setLine( (int)position[0] ); + if(hasProp[1]) + range.setCol( (int)position[1] ); + if(hasProp[2]) + range.setEndLine( (int)position[2] ); + if(hasProp[3]) + range.setEndCol( (int)position[3] ); + if(hasProp[4]) + range.setWideLine( (int)position[4] ); + if(hasProp[5]) + range.setWideCol( (int)position[5] ); + if(hasProp[6]) + range.setWideEndLine( (int)position[6] ); + if(hasProp[7]) + range.setWideEndCol( (int)position[7] ); + dynamic_cast(obj->_nativeObj)->setPosition( range ); + return nullptr; +} + + +}}}} //end of namespaces \ No newline at end of file diff --git a/lib/javascript/addon/src/ChainExpressionWrapper.cc b/lib/javascript/addon/src/ChainExpressionWrapper.cc new file mode 100644 index 0000000..ec92dd1 --- /dev/null +++ b/lib/javascript/addon/src/ChainExpressionWrapper.cc @@ -0,0 +1,256 @@ +#include "../inc/ChainExpressionWrapper.h" +#include +namespace columbus { namespace javascript { namespace asg { namespace addon { + +napi_ref ChainExpressionWrapper::constructor; + +ChainExpressionWrapper::ChainExpressionWrapper(): env_(nullptr), wrapper_(nullptr) {} + +ChainExpressionWrapper::~ChainExpressionWrapper(){ napi_delete_reference(env_, wrapper_); } + +void ChainExpressionWrapper::Destructor(napi_env env, void* nativeObject, void* ){ + ChainExpressionWrapper* obj = reinterpret_cast(nativeObject); + //delete obj->_nativeObj; + obj->~ChainExpressionWrapper(); +} +napi_value ChainExpressionWrapper::Init(napi_env env, napi_value& exports) { + napi_status status; + napi_property_descriptor props [] = { + DECLARE_NAPI_METHOD( "setExpression", setExpression), + DECLARE_NAPI_METHOD( "addComments", addComments), + DECLARE_NAPI_METHOD("setPath", setPath), + DECLARE_NAPI_METHOD("setPosition", setPosition), + }; + + napi_value cons; + status = napi_define_class(env, "ChainExpressionWrapper", NAPI_AUTO_LENGTH, New, nullptr, sizeof(props) / sizeof(*props), props, &cons ); + assert(status == napi_ok); + + status = napi_create_reference(env, cons, 1, &constructor); + assert(status == napi_ok); + + return exports; +} +napi_value ChainExpressionWrapper::New(napi_env env, napi_callback_info info) { + napi_status status; + napi_value jsthis; + + status = napi_get_cb_info(env, info, 0, nullptr, &jsthis, nullptr); + assert(status == napi_ok); + + ChainExpressionWrapper* obj = new ChainExpressionWrapper(); + obj->env_ = env; + status = napi_wrap(env, jsthis, reinterpret_cast(obj), ChainExpressionWrapper::Destructor, nullptr, &obj->wrapper_); + assert(status == napi_ok); + + return jsthis; +} + + +napi_status ChainExpressionWrapper::NewInstance(napi_env env, expression::ChainExpression* arg, napi_value* instance) { + + napi_status status; + napi_value cons; + + status = napi_get_reference_value(env, constructor, &cons); + if(status != napi_ok) return status; + + status = napi_new_instance(env, cons, 0, nullptr, instance); + if(status != napi_ok) return status; + + ChainExpressionWrapper* obj; + status = napi_unwrap(env, *instance, reinterpret_cast(&obj)); + obj->_nativeObj = arg; + return napi_ok; +} + +napi_value ChainExpressionWrapper::setExpression(napi_env env, napi_callback_info info){ + napi_status status; + napi_value jsthis; + size_t argc = 1; + napi_value args[1]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments."); + return nullptr; + } + + ChainExpressionWrapper* obj; + BaseWrapper* param; + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + status = napi_unwrap(env, args[0], reinterpret_cast(¶m)); + assert(status == napi_ok); + + columbus::javascript::asg::expression::ChainExpression* source = dynamic_cast(obj->_nativeObj); + columbus::javascript::asg::expression::ChainElement* target = dynamic_cast(param->_nativeObj); + + if(source == nullptr){ + status = napi_throw_error(env, nullptr, "Cannot cast expression::ChainExpression" ); + } + if(target == nullptr){ + status = napi_throw_error(env, nullptr, "Cannot cast expression::ChainElement" ); + } + + source->setExpression(target); + return nullptr; +} +napi_value ChainExpressionWrapper::addComments(napi_env env, napi_callback_info info){ + napi_status status; + napi_value jsthis; + size_t argc = 1; + napi_value args[1]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments."); + return nullptr; + } + + ChainExpressionWrapper* obj; + BaseWrapper* param; + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + status = napi_unwrap(env, args[0], reinterpret_cast(¶m)); + assert(status == napi_ok); + + columbus::javascript::asg::expression::ChainExpression* source = dynamic_cast(obj->_nativeObj); + columbus::javascript::asg::base::Comment* target = dynamic_cast(param->_nativeObj); + + if(source == nullptr){ + status = napi_throw_error(env, nullptr, "Cannot cast expression::ChainExpression" ); + } + if(target == nullptr){ + status = napi_throw_error(env, nullptr, "Cannot cast base::Comment" ); + } + + source->addComments(target); + return nullptr; +} +napi_value ChainExpressionWrapper::setPath(napi_env env, napi_callback_info info) { + napi_status status; + napi_value jsthis; + size_t argc = 1; + napi_value args[1]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments"); + return nullptr; + } + + ChainExpressionWrapper* obj; + napi_valuetype valuetype; + status = napi_typeof(env, args[0], &valuetype); + assert(status == napi_ok); + + if (valuetype != napi_string) { + napi_throw_type_error(env, nullptr, "Argument should be a string!"); + return nullptr; + } + + char buffer[1024]; + size_t buffer_size = 1024, result_size = 0; + status = napi_get_value_string_utf8(env, args[0], buffer, buffer_size, &result_size); + assert(status == napi_ok); + + std::string path(buffer); + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + Range range = dynamic_cast(obj->_nativeObj)->getPosition(); + range.setPath( path ); + dynamic_cast(obj->_nativeObj)->setPosition( range ); + return nullptr; +} + + +napi_value ChainExpressionWrapper::setPosition(napi_env env, napi_callback_info info) { + napi_status status; + napi_value jsthis; + size_t argc = 8; + napi_value args[8]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1 && argc != 8) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments. Use a simple object with the positions or pass 8 parameters: line, col, endline, endcol and their wide equivalents!"); + return nullptr; + } + + ChainExpressionWrapper* obj; + napi_valuetype valuetype[8]; + int32_t position[8]; + bool hasProp[8]; + if(argc == 1){ + status = napi_typeof(env, args[0], &valuetype[0]); + assert(status == napi_ok); + + if(valuetype[0] != napi_object){ + napi_throw_type_error(env, nullptr, "Argument should be an object!"); + return nullptr; + } + + std::string props[] = {"line", "col", "endline", "endcol", "wideline", "widecol", "wideendline", "wideendcol",}; + + for(int i = 0; i < 8; ++i){ + status = napi_has_named_property(env, args[0], props[i].c_str(), &hasProp[i]); + assert(status == napi_ok); + napi_value value; + if(hasProp[i]){ + status = napi_get_named_property(env, args[0], props[i].c_str(), &value); + assert(status == napi_ok); + status = napi_get_value_int32(env, value, &position[i]); + assert(status == napi_ok); + } + + } + } + else{ + for(int i = 0; i < 8; ++i){ + status = napi_typeof(env, args[i], &valuetype[i]); + assert(status == napi_ok); + if(valuetype[i] != napi_number){ + napi_throw_type_error(env, nullptr, "Argument should be an integer!"); + return nullptr; + } + status = napi_get_value_int32(env, args[i], &position[i]); + assert(status == napi_ok); + } + for(int i = 0; i < 8; ++i){ + hasProp[i] = true; + } + } + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + Range range = dynamic_cast(obj->_nativeObj)->getPosition(); + + if(hasProp[0]) + range.setLine( (int)position[0] ); + if(hasProp[1]) + range.setCol( (int)position[1] ); + if(hasProp[2]) + range.setEndLine( (int)position[2] ); + if(hasProp[3]) + range.setEndCol( (int)position[3] ); + if(hasProp[4]) + range.setWideLine( (int)position[4] ); + if(hasProp[5]) + range.setWideCol( (int)position[5] ); + if(hasProp[6]) + range.setWideEndLine( (int)position[6] ); + if(hasProp[7]) + range.setWideEndCol( (int)position[7] ); + dynamic_cast(obj->_nativeObj)->setPosition( range ); + return nullptr; +} + + +}}}} //end of namespaces \ No newline at end of file diff --git a/lib/javascript/addon/src/ClassBodyWrapper.cc b/lib/javascript/addon/src/ClassBodyWrapper.cc index 4d7bc7a..98eab2c 100644 --- a/lib/javascript/addon/src/ClassBodyWrapper.cc +++ b/lib/javascript/addon/src/ClassBodyWrapper.cc @@ -86,13 +86,13 @@ napi_value ClassBodyWrapper::addBody(napi_env env, napi_callback_info info){ assert(status == napi_ok); columbus::javascript::asg::structure::ClassBody* source = dynamic_cast(obj->_nativeObj); - columbus::javascript::asg::structure::MethodDefinition* target = dynamic_cast(param->_nativeObj); + columbus::javascript::asg::base::Positioned* target = dynamic_cast(param->_nativeObj); if(source == nullptr){ status = napi_throw_error(env, nullptr, "Cannot cast structure::ClassBody" ); } if(target == nullptr){ - status = napi_throw_error(env, nullptr, "Cannot cast structure::MethodDefinition" ); + status = napi_throw_error(env, nullptr, "Cannot cast base::Positioned" ); } source->addBody(target); diff --git a/lib/javascript/addon/src/ExportAllDeclarationWrapper.cc b/lib/javascript/addon/src/ExportAllDeclarationWrapper.cc index 7b15c61..ec881d4 100644 --- a/lib/javascript/addon/src/ExportAllDeclarationWrapper.cc +++ b/lib/javascript/addon/src/ExportAllDeclarationWrapper.cc @@ -17,6 +17,7 @@ napi_value ExportAllDeclarationWrapper::Init(napi_env env, napi_value& exports) napi_status status; napi_property_descriptor props [] = { DECLARE_NAPI_METHOD( "setSource", setSource), + DECLARE_NAPI_METHOD( "setExported", setExported), DECLARE_NAPI_METHOD( "addComments", addComments), DECLARE_NAPI_METHOD("setPath", setPath), DECLARE_NAPI_METHOD("setPosition", setPosition), @@ -98,6 +99,40 @@ napi_value ExportAllDeclarationWrapper::setSource(napi_env env, napi_callback_in source->setSource(target); return nullptr; } +napi_value ExportAllDeclarationWrapper::setExported(napi_env env, napi_callback_info info){ + napi_status status; + napi_value jsthis; + size_t argc = 1; + napi_value args[1]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments."); + return nullptr; + } + + ExportAllDeclarationWrapper* obj; + BaseWrapper* param; + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + status = napi_unwrap(env, args[0], reinterpret_cast(¶m)); + assert(status == napi_ok); + + columbus::javascript::asg::declaration::ExportAllDeclaration* source = dynamic_cast(obj->_nativeObj); + columbus::javascript::asg::expression::Identifier* target = dynamic_cast(param->_nativeObj); + + if(source == nullptr){ + status = napi_throw_error(env, nullptr, "Cannot cast declaration::ExportAllDeclaration" ); + } + if(target == nullptr){ + status = napi_throw_error(env, nullptr, "Cannot cast expression::Identifier" ); + } + + source->setExported(target); + return nullptr; +} napi_value ExportAllDeclarationWrapper::addComments(napi_env env, napi_callback_info info){ napi_status status; napi_value jsthis; diff --git a/lib/javascript/addon/src/ForOfStatementWrapper.cc b/lib/javascript/addon/src/ForOfStatementWrapper.cc index 1a300dc..ad7ae28 100644 --- a/lib/javascript/addon/src/ForOfStatementWrapper.cc +++ b/lib/javascript/addon/src/ForOfStatementWrapper.cc @@ -20,7 +20,7 @@ napi_value ForOfStatementWrapper::Init(napi_env env, napi_value& exports) { DECLARE_NAPI_METHOD( "setBody", setBody), DECLARE_NAPI_METHOD( "setLeft", setLeft), DECLARE_NAPI_METHOD( "addComments", addComments), - DECLARE_NAPI_METHOD("setAsync", setAsync), + DECLARE_NAPI_METHOD("setAwait", setAwait), DECLARE_NAPI_METHOD("setPath", setPath), DECLARE_NAPI_METHOD("setPosition", setPosition), }; @@ -203,7 +203,7 @@ napi_value ForOfStatementWrapper::addComments(napi_env env, napi_callback_info i source->addComments(target); return nullptr; } -napi_value ForOfStatementWrapper::setAsync(napi_env env, napi_callback_info info){ +napi_value ForOfStatementWrapper::setAwait(napi_env env, napi_callback_info info){ napi_status status; napi_value jsthis; size_t argc = 1; @@ -232,7 +232,7 @@ napi_value ForOfStatementWrapper::setAsync(napi_env env, napi_callback_info info bool b; status = napi_get_value_bool(env, args[0], &b); assert(status == napi_ok); - dynamic_cast(obj->_nativeObj)->setAsync( b ); + dynamic_cast(obj->_nativeObj)->setAwait( b ); return nullptr; } napi_value ForOfStatementWrapper::setPath(napi_env env, napi_callback_info info) { diff --git a/lib/javascript/addon/src/ImportExpressionWrapper.cc b/lib/javascript/addon/src/ImportExpressionWrapper.cc new file mode 100644 index 0000000..c7bc17c --- /dev/null +++ b/lib/javascript/addon/src/ImportExpressionWrapper.cc @@ -0,0 +1,256 @@ +#include "../inc/ImportExpressionWrapper.h" +#include +namespace columbus { namespace javascript { namespace asg { namespace addon { + +napi_ref ImportExpressionWrapper::constructor; + +ImportExpressionWrapper::ImportExpressionWrapper(): env_(nullptr), wrapper_(nullptr) {} + +ImportExpressionWrapper::~ImportExpressionWrapper(){ napi_delete_reference(env_, wrapper_); } + +void ImportExpressionWrapper::Destructor(napi_env env, void* nativeObject, void* ){ + ImportExpressionWrapper* obj = reinterpret_cast(nativeObject); + //delete obj->_nativeObj; + obj->~ImportExpressionWrapper(); +} +napi_value ImportExpressionWrapper::Init(napi_env env, napi_value& exports) { + napi_status status; + napi_property_descriptor props [] = { + DECLARE_NAPI_METHOD( "setSource", setSource), + DECLARE_NAPI_METHOD( "addComments", addComments), + DECLARE_NAPI_METHOD("setPath", setPath), + DECLARE_NAPI_METHOD("setPosition", setPosition), + }; + + napi_value cons; + status = napi_define_class(env, "ImportExpressionWrapper", NAPI_AUTO_LENGTH, New, nullptr, sizeof(props) / sizeof(*props), props, &cons ); + assert(status == napi_ok); + + status = napi_create_reference(env, cons, 1, &constructor); + assert(status == napi_ok); + + return exports; +} +napi_value ImportExpressionWrapper::New(napi_env env, napi_callback_info info) { + napi_status status; + napi_value jsthis; + + status = napi_get_cb_info(env, info, 0, nullptr, &jsthis, nullptr); + assert(status == napi_ok); + + ImportExpressionWrapper* obj = new ImportExpressionWrapper(); + obj->env_ = env; + status = napi_wrap(env, jsthis, reinterpret_cast(obj), ImportExpressionWrapper::Destructor, nullptr, &obj->wrapper_); + assert(status == napi_ok); + + return jsthis; +} + + +napi_status ImportExpressionWrapper::NewInstance(napi_env env, expression::ImportExpression* arg, napi_value* instance) { + + napi_status status; + napi_value cons; + + status = napi_get_reference_value(env, constructor, &cons); + if(status != napi_ok) return status; + + status = napi_new_instance(env, cons, 0, nullptr, instance); + if(status != napi_ok) return status; + + ImportExpressionWrapper* obj; + status = napi_unwrap(env, *instance, reinterpret_cast(&obj)); + obj->_nativeObj = arg; + return napi_ok; +} + +napi_value ImportExpressionWrapper::setSource(napi_env env, napi_callback_info info){ + napi_status status; + napi_value jsthis; + size_t argc = 1; + napi_value args[1]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments."); + return nullptr; + } + + ImportExpressionWrapper* obj; + BaseWrapper* param; + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + status = napi_unwrap(env, args[0], reinterpret_cast(¶m)); + assert(status == napi_ok); + + columbus::javascript::asg::expression::ImportExpression* source = dynamic_cast(obj->_nativeObj); + columbus::javascript::asg::expression::Expression* target = dynamic_cast(param->_nativeObj); + + if(source == nullptr){ + status = napi_throw_error(env, nullptr, "Cannot cast expression::ImportExpression" ); + } + if(target == nullptr){ + status = napi_throw_error(env, nullptr, "Cannot cast expression::Expression" ); + } + + source->setSource(target); + return nullptr; +} +napi_value ImportExpressionWrapper::addComments(napi_env env, napi_callback_info info){ + napi_status status; + napi_value jsthis; + size_t argc = 1; + napi_value args[1]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments."); + return nullptr; + } + + ImportExpressionWrapper* obj; + BaseWrapper* param; + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + status = napi_unwrap(env, args[0], reinterpret_cast(¶m)); + assert(status == napi_ok); + + columbus::javascript::asg::expression::ImportExpression* source = dynamic_cast(obj->_nativeObj); + columbus::javascript::asg::base::Comment* target = dynamic_cast(param->_nativeObj); + + if(source == nullptr){ + status = napi_throw_error(env, nullptr, "Cannot cast expression::ImportExpression" ); + } + if(target == nullptr){ + status = napi_throw_error(env, nullptr, "Cannot cast base::Comment" ); + } + + source->addComments(target); + return nullptr; +} +napi_value ImportExpressionWrapper::setPath(napi_env env, napi_callback_info info) { + napi_status status; + napi_value jsthis; + size_t argc = 1; + napi_value args[1]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments"); + return nullptr; + } + + ImportExpressionWrapper* obj; + napi_valuetype valuetype; + status = napi_typeof(env, args[0], &valuetype); + assert(status == napi_ok); + + if (valuetype != napi_string) { + napi_throw_type_error(env, nullptr, "Argument should be a string!"); + return nullptr; + } + + char buffer[1024]; + size_t buffer_size = 1024, result_size = 0; + status = napi_get_value_string_utf8(env, args[0], buffer, buffer_size, &result_size); + assert(status == napi_ok); + + std::string path(buffer); + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + Range range = dynamic_cast(obj->_nativeObj)->getPosition(); + range.setPath( path ); + dynamic_cast(obj->_nativeObj)->setPosition( range ); + return nullptr; +} + + +napi_value ImportExpressionWrapper::setPosition(napi_env env, napi_callback_info info) { + napi_status status; + napi_value jsthis; + size_t argc = 8; + napi_value args[8]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1 && argc != 8) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments. Use a simple object with the positions or pass 8 parameters: line, col, endline, endcol and their wide equivalents!"); + return nullptr; + } + + ImportExpressionWrapper* obj; + napi_valuetype valuetype[8]; + int32_t position[8]; + bool hasProp[8]; + if(argc == 1){ + status = napi_typeof(env, args[0], &valuetype[0]); + assert(status == napi_ok); + + if(valuetype[0] != napi_object){ + napi_throw_type_error(env, nullptr, "Argument should be an object!"); + return nullptr; + } + + std::string props[] = {"line", "col", "endline", "endcol", "wideline", "widecol", "wideendline", "wideendcol",}; + + for(int i = 0; i < 8; ++i){ + status = napi_has_named_property(env, args[0], props[i].c_str(), &hasProp[i]); + assert(status == napi_ok); + napi_value value; + if(hasProp[i]){ + status = napi_get_named_property(env, args[0], props[i].c_str(), &value); + assert(status == napi_ok); + status = napi_get_value_int32(env, value, &position[i]); + assert(status == napi_ok); + } + + } + } + else{ + for(int i = 0; i < 8; ++i){ + status = napi_typeof(env, args[i], &valuetype[i]); + assert(status == napi_ok); + if(valuetype[i] != napi_number){ + napi_throw_type_error(env, nullptr, "Argument should be an integer!"); + return nullptr; + } + status = napi_get_value_int32(env, args[i], &position[i]); + assert(status == napi_ok); + } + for(int i = 0; i < 8; ++i){ + hasProp[i] = true; + } + } + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + Range range = dynamic_cast(obj->_nativeObj)->getPosition(); + + if(hasProp[0]) + range.setLine( (int)position[0] ); + if(hasProp[1]) + range.setCol( (int)position[1] ); + if(hasProp[2]) + range.setEndLine( (int)position[2] ); + if(hasProp[3]) + range.setEndCol( (int)position[3] ); + if(hasProp[4]) + range.setWideLine( (int)position[4] ); + if(hasProp[5]) + range.setWideCol( (int)position[5] ); + if(hasProp[6]) + range.setWideEndLine( (int)position[6] ); + if(hasProp[7]) + range.setWideEndCol( (int)position[7] ); + dynamic_cast(obj->_nativeObj)->setPosition( range ); + return nullptr; +} + + +}}}} //end of namespaces \ No newline at end of file diff --git a/lib/javascript/addon/src/LogicalExpressionWrapper.cc b/lib/javascript/addon/src/LogicalExpressionWrapper.cc index 5749f00..54a8a7c 100644 --- a/lib/javascript/addon/src/LogicalExpressionWrapper.cc +++ b/lib/javascript/addon/src/LogicalExpressionWrapper.cc @@ -207,6 +207,9 @@ napi_value LogicalExpressionWrapper::setOperator(napi_env env, napi_callback_inf if( param == "looOr" ){ dynamic_cast(obj->_nativeObj)->setOperator( looOr ); } + if( param == "looNullishCoalescing" ){ + dynamic_cast(obj->_nativeObj)->setOperator( looNullishCoalescing ); + } return nullptr; } napi_value LogicalExpressionWrapper::setPath(napi_env env, napi_callback_info info) { diff --git a/lib/javascript/addon/src/MemberExpressionWrapper.cc b/lib/javascript/addon/src/MemberExpressionWrapper.cc index b3cba4b..e90498b 100644 --- a/lib/javascript/addon/src/MemberExpressionWrapper.cc +++ b/lib/javascript/addon/src/MemberExpressionWrapper.cc @@ -22,6 +22,7 @@ napi_value MemberExpressionWrapper::Init(napi_env env, napi_value& exports) { DECLARE_NAPI_METHOD("setComputed", setComputed), DECLARE_NAPI_METHOD("setPath", setPath), DECLARE_NAPI_METHOD("setPosition", setPosition), + DECLARE_NAPI_METHOD("setOptional", setOptional), }; napi_value cons; @@ -88,13 +89,13 @@ napi_value MemberExpressionWrapper::setProperty(napi_env env, napi_callback_info assert(status == napi_ok); columbus::javascript::asg::expression::MemberExpression* source = dynamic_cast(obj->_nativeObj); - columbus::javascript::asg::expression::Expression* target = dynamic_cast(param->_nativeObj); + columbus::javascript::asg::base::Positioned* target = dynamic_cast(param->_nativeObj); if(source == nullptr){ status = napi_throw_error(env, nullptr, "Cannot cast expression::MemberExpression" ); } if(target == nullptr){ - status = napi_throw_error(env, nullptr, "Cannot cast expression::Expression" ); + status = napi_throw_error(env, nullptr, "Cannot cast base::Positioned" ); } source->setProperty(target); @@ -321,4 +322,36 @@ napi_value MemberExpressionWrapper::setPosition(napi_env env, napi_callback_info } +napi_value MemberExpressionWrapper::setOptional(napi_env env, napi_callback_info info){ + napi_status status; + napi_value jsthis; + size_t argc = 1; + napi_value args[1]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments."); + return nullptr; + } + + MemberExpressionWrapper* obj; + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + napi_valuetype paramtype; + status = napi_typeof(env, args[0], ¶mtype); + assert(status == napi_ok); + + if(paramtype != napi_boolean){ + napi_throw_type_error(env, nullptr, "Argument should be a boolean!"); + return nullptr; + } + + bool b; + status = napi_get_value_bool(env, args[0], &b); + assert(status == napi_ok); + dynamic_cast(obj->_nativeObj)->setOptional( b ); + return nullptr; +} }}}} //end of namespaces \ No newline at end of file diff --git a/lib/javascript/addon/src/MethodDefinitionWrapper.cc b/lib/javascript/addon/src/MethodDefinitionWrapper.cc index 88481b3..89b3c8a 100644 --- a/lib/javascript/addon/src/MethodDefinitionWrapper.cc +++ b/lib/javascript/addon/src/MethodDefinitionWrapper.cc @@ -90,13 +90,13 @@ napi_value MethodDefinitionWrapper::setKey(napi_env env, napi_callback_info info assert(status == napi_ok); columbus::javascript::asg::structure::MethodDefinition* source = dynamic_cast(obj->_nativeObj); - columbus::javascript::asg::expression::Expression* target = dynamic_cast(param->_nativeObj); + columbus::javascript::asg::base::Positioned* target = dynamic_cast(param->_nativeObj); if(source == nullptr){ status = napi_throw_error(env, nullptr, "Cannot cast structure::MethodDefinition" ); } if(target == nullptr){ - status = napi_throw_error(env, nullptr, "Cannot cast expression::Expression" ); + status = napi_throw_error(env, nullptr, "Cannot cast base::Positioned" ); } source->setKey(target); diff --git a/lib/javascript/addon/src/PrivateIdentifierWrapper.cc b/lib/javascript/addon/src/PrivateIdentifierWrapper.cc new file mode 100644 index 0000000..6d87d75 --- /dev/null +++ b/lib/javascript/addon/src/PrivateIdentifierWrapper.cc @@ -0,0 +1,262 @@ +#include "../inc/PrivateIdentifierWrapper.h" +#include +namespace columbus { namespace javascript { namespace asg { namespace addon { + +napi_ref PrivateIdentifierWrapper::constructor; + +PrivateIdentifierWrapper::PrivateIdentifierWrapper(): env_(nullptr), wrapper_(nullptr) {} + +PrivateIdentifierWrapper::~PrivateIdentifierWrapper(){ napi_delete_reference(env_, wrapper_); } + +void PrivateIdentifierWrapper::Destructor(napi_env env, void* nativeObject, void* ){ + PrivateIdentifierWrapper* obj = reinterpret_cast(nativeObject); + //delete obj->_nativeObj; + obj->~PrivateIdentifierWrapper(); +} +napi_value PrivateIdentifierWrapper::Init(napi_env env, napi_value& exports) { + napi_status status; + napi_property_descriptor props [] = { + DECLARE_NAPI_METHOD( "addComments", addComments), + DECLARE_NAPI_METHOD("setPath", setPath), + DECLARE_NAPI_METHOD("setPosition", setPosition), + DECLARE_NAPI_METHOD("setName", setName), + }; + + napi_value cons; + status = napi_define_class(env, "PrivateIdentifierWrapper", NAPI_AUTO_LENGTH, New, nullptr, sizeof(props) / sizeof(*props), props, &cons ); + assert(status == napi_ok); + + status = napi_create_reference(env, cons, 1, &constructor); + assert(status == napi_ok); + + return exports; +} +napi_value PrivateIdentifierWrapper::New(napi_env env, napi_callback_info info) { + napi_status status; + napi_value jsthis; + + status = napi_get_cb_info(env, info, 0, nullptr, &jsthis, nullptr); + assert(status == napi_ok); + + PrivateIdentifierWrapper* obj = new PrivateIdentifierWrapper(); + obj->env_ = env; + status = napi_wrap(env, jsthis, reinterpret_cast(obj), PrivateIdentifierWrapper::Destructor, nullptr, &obj->wrapper_); + assert(status == napi_ok); + + return jsthis; +} + + +napi_status PrivateIdentifierWrapper::NewInstance(napi_env env, expression::PrivateIdentifier* arg, napi_value* instance) { + + napi_status status; + napi_value cons; + + status = napi_get_reference_value(env, constructor, &cons); + if(status != napi_ok) return status; + + status = napi_new_instance(env, cons, 0, nullptr, instance); + if(status != napi_ok) return status; + + PrivateIdentifierWrapper* obj; + status = napi_unwrap(env, *instance, reinterpret_cast(&obj)); + obj->_nativeObj = arg; + return napi_ok; +} + +napi_value PrivateIdentifierWrapper::addComments(napi_env env, napi_callback_info info){ + napi_status status; + napi_value jsthis; + size_t argc = 1; + napi_value args[1]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments."); + return nullptr; + } + + PrivateIdentifierWrapper* obj; + BaseWrapper* param; + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + status = napi_unwrap(env, args[0], reinterpret_cast(¶m)); + assert(status == napi_ok); + + columbus::javascript::asg::expression::PrivateIdentifier* source = dynamic_cast(obj->_nativeObj); + columbus::javascript::asg::base::Comment* target = dynamic_cast(param->_nativeObj); + + if(source == nullptr){ + status = napi_throw_error(env, nullptr, "Cannot cast expression::PrivateIdentifier" ); + } + if(target == nullptr){ + status = napi_throw_error(env, nullptr, "Cannot cast base::Comment" ); + } + + source->addComments(target); + return nullptr; +} +napi_value PrivateIdentifierWrapper::setPath(napi_env env, napi_callback_info info) { + napi_status status; + napi_value jsthis; + size_t argc = 1; + napi_value args[1]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments"); + return nullptr; + } + + PrivateIdentifierWrapper* obj; + napi_valuetype valuetype; + status = napi_typeof(env, args[0], &valuetype); + assert(status == napi_ok); + + if (valuetype != napi_string) { + napi_throw_type_error(env, nullptr, "Argument should be a string!"); + return nullptr; + } + + char buffer[1024]; + size_t buffer_size = 1024, result_size = 0; + status = napi_get_value_string_utf8(env, args[0], buffer, buffer_size, &result_size); + assert(status == napi_ok); + + std::string path(buffer); + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + Range range = dynamic_cast(obj->_nativeObj)->getPosition(); + range.setPath( path ); + dynamic_cast(obj->_nativeObj)->setPosition( range ); + return nullptr; +} + + +napi_value PrivateIdentifierWrapper::setPosition(napi_env env, napi_callback_info info) { + napi_status status; + napi_value jsthis; + size_t argc = 8; + napi_value args[8]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1 && argc != 8) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments. Use a simple object with the positions or pass 8 parameters: line, col, endline, endcol and their wide equivalents!"); + return nullptr; + } + + PrivateIdentifierWrapper* obj; + napi_valuetype valuetype[8]; + int32_t position[8]; + bool hasProp[8]; + if(argc == 1){ + status = napi_typeof(env, args[0], &valuetype[0]); + assert(status == napi_ok); + + if(valuetype[0] != napi_object){ + napi_throw_type_error(env, nullptr, "Argument should be an object!"); + return nullptr; + } + + std::string props[] = {"line", "col", "endline", "endcol", "wideline", "widecol", "wideendline", "wideendcol",}; + + for(int i = 0; i < 8; ++i){ + status = napi_has_named_property(env, args[0], props[i].c_str(), &hasProp[i]); + assert(status == napi_ok); + napi_value value; + if(hasProp[i]){ + status = napi_get_named_property(env, args[0], props[i].c_str(), &value); + assert(status == napi_ok); + status = napi_get_value_int32(env, value, &position[i]); + assert(status == napi_ok); + } + + } + } + else{ + for(int i = 0; i < 8; ++i){ + status = napi_typeof(env, args[i], &valuetype[i]); + assert(status == napi_ok); + if(valuetype[i] != napi_number){ + napi_throw_type_error(env, nullptr, "Argument should be an integer!"); + return nullptr; + } + status = napi_get_value_int32(env, args[i], &position[i]); + assert(status == napi_ok); + } + for(int i = 0; i < 8; ++i){ + hasProp[i] = true; + } + } + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + Range range = dynamic_cast(obj->_nativeObj)->getPosition(); + + if(hasProp[0]) + range.setLine( (int)position[0] ); + if(hasProp[1]) + range.setCol( (int)position[1] ); + if(hasProp[2]) + range.setEndLine( (int)position[2] ); + if(hasProp[3]) + range.setEndCol( (int)position[3] ); + if(hasProp[4]) + range.setWideLine( (int)position[4] ); + if(hasProp[5]) + range.setWideCol( (int)position[5] ); + if(hasProp[6]) + range.setWideEndLine( (int)position[6] ); + if(hasProp[7]) + range.setWideEndCol( (int)position[7] ); + dynamic_cast(obj->_nativeObj)->setPosition( range ); + return nullptr; +} + + +napi_value PrivateIdentifierWrapper::setName(napi_env env, napi_callback_info info){ + napi_status status; + napi_value jsthis; + size_t argc = 1; + napi_value args[1]; + status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); + assert(status == napi_ok); + + if (argc != 1) { + napi_throw_type_error(env, nullptr, "Wrong number of arguments."); + return nullptr; + } + + PrivateIdentifierWrapper* obj; + status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); + assert(status == napi_ok); + + napi_valuetype paramtype; + status = napi_typeof(env, args[0], ¶mtype); + assert(status == napi_ok); + + if(paramtype != napi_string && paramtype != napi_null){ + napi_throw_type_error(env, nullptr, "Argument should be a string!"); + return nullptr; + } + + if(paramtype == napi_null){ + dynamic_cast(obj->_nativeObj)->setName( std::string("null") ); + } + else{ + char buffer[1024]; + size_t buffer_size = 1024, result_size = 0; + status = napi_get_value_string_utf8(env, args[0], buffer, buffer_size, &result_size); + assert(status == napi_ok); + + std::string param(buffer); + dynamic_cast(obj->_nativeObj)->setName( param ); + } + return nullptr; +} +}}}} //end of namespaces \ No newline at end of file diff --git a/lib/javascript/addon/src/AssignmentPropertyWrapper.cc b/lib/javascript/addon/src/PropertyDefinitionWrapper.cc similarity index 64% rename from lib/javascript/addon/src/AssignmentPropertyWrapper.cc rename to lib/javascript/addon/src/PropertyDefinitionWrapper.cc index f055201..2210ecb 100644 --- a/lib/javascript/addon/src/AssignmentPropertyWrapper.cc +++ b/lib/javascript/addon/src/PropertyDefinitionWrapper.cc @@ -1,34 +1,32 @@ -#include "../inc/AssignmentPropertyWrapper.h" +#include "../inc/PropertyDefinitionWrapper.h" #include namespace columbus { namespace javascript { namespace asg { namespace addon { -napi_ref AssignmentPropertyWrapper::constructor; +napi_ref PropertyDefinitionWrapper::constructor; -AssignmentPropertyWrapper::AssignmentPropertyWrapper(): env_(nullptr), wrapper_(nullptr) {} +PropertyDefinitionWrapper::PropertyDefinitionWrapper(): env_(nullptr), wrapper_(nullptr) {} -AssignmentPropertyWrapper::~AssignmentPropertyWrapper(){ napi_delete_reference(env_, wrapper_); } +PropertyDefinitionWrapper::~PropertyDefinitionWrapper(){ napi_delete_reference(env_, wrapper_); } -void AssignmentPropertyWrapper::Destructor(napi_env env, void* nativeObject, void* ){ - AssignmentPropertyWrapper* obj = reinterpret_cast(nativeObject); +void PropertyDefinitionWrapper::Destructor(napi_env env, void* nativeObject, void* ){ + PropertyDefinitionWrapper* obj = reinterpret_cast(nativeObject); //delete obj->_nativeObj; - obj->~AssignmentPropertyWrapper(); + obj->~PropertyDefinitionWrapper(); } -napi_value AssignmentPropertyWrapper::Init(napi_env env, napi_value& exports) { +napi_value PropertyDefinitionWrapper::Init(napi_env env, napi_value& exports) { napi_status status; napi_property_descriptor props [] = { - DECLARE_NAPI_METHOD( "setValue", setValue), DECLARE_NAPI_METHOD( "setKey", setKey), + DECLARE_NAPI_METHOD( "setValue", setValue), DECLARE_NAPI_METHOD( "addComments", addComments), - DECLARE_NAPI_METHOD("setKind", setKind), - DECLARE_NAPI_METHOD("setMethod", setMethod), - DECLARE_NAPI_METHOD("setShorthand", setShorthand), DECLARE_NAPI_METHOD("setComputed", setComputed), + DECLARE_NAPI_METHOD("setStatic", setStatic), DECLARE_NAPI_METHOD("setPath", setPath), DECLARE_NAPI_METHOD("setPosition", setPosition), }; napi_value cons; - status = napi_define_class(env, "AssignmentPropertyWrapper", NAPI_AUTO_LENGTH, New, nullptr, sizeof(props) / sizeof(*props), props, &cons ); + status = napi_define_class(env, "PropertyDefinitionWrapper", NAPI_AUTO_LENGTH, New, nullptr, sizeof(props) / sizeof(*props), props, &cons ); assert(status == napi_ok); status = napi_create_reference(env, cons, 1, &constructor); @@ -36,23 +34,23 @@ napi_value AssignmentPropertyWrapper::Init(napi_env env, napi_value& exports) { return exports; } -napi_value AssignmentPropertyWrapper::New(napi_env env, napi_callback_info info) { +napi_value PropertyDefinitionWrapper::New(napi_env env, napi_callback_info info) { napi_status status; napi_value jsthis; status = napi_get_cb_info(env, info, 0, nullptr, &jsthis, nullptr); assert(status == napi_ok); - AssignmentPropertyWrapper* obj = new AssignmentPropertyWrapper(); + PropertyDefinitionWrapper* obj = new PropertyDefinitionWrapper(); obj->env_ = env; - status = napi_wrap(env, jsthis, reinterpret_cast(obj), AssignmentPropertyWrapper::Destructor, nullptr, &obj->wrapper_); + status = napi_wrap(env, jsthis, reinterpret_cast(obj), PropertyDefinitionWrapper::Destructor, nullptr, &obj->wrapper_); assert(status == napi_ok); return jsthis; } -napi_status AssignmentPropertyWrapper::NewInstance(napi_env env, expression::AssignmentProperty* arg, napi_value* instance) { +napi_status PropertyDefinitionWrapper::NewInstance(napi_env env, structure::PropertyDefinition* arg, napi_value* instance) { napi_status status; napi_value cons; @@ -63,13 +61,13 @@ napi_status AssignmentPropertyWrapper::NewInstance(napi_env env, expression::Ass status = napi_new_instance(env, cons, 0, nullptr, instance); if(status != napi_ok) return status; - AssignmentPropertyWrapper* obj; + PropertyDefinitionWrapper* obj; status = napi_unwrap(env, *instance, reinterpret_cast(&obj)); obj->_nativeObj = arg; return napi_ok; } -napi_value AssignmentPropertyWrapper::setValue(napi_env env, napi_callback_info info){ +napi_value PropertyDefinitionWrapper::setKey(napi_env env, napi_callback_info info){ napi_status status; napi_value jsthis; size_t argc = 1; @@ -82,7 +80,7 @@ napi_value AssignmentPropertyWrapper::setValue(napi_env env, napi_callback_info return nullptr; } - AssignmentPropertyWrapper* obj; + PropertyDefinitionWrapper* obj; BaseWrapper* param; status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); assert(status == napi_ok); @@ -90,20 +88,20 @@ napi_value AssignmentPropertyWrapper::setValue(napi_env env, napi_callback_info status = napi_unwrap(env, args[0], reinterpret_cast(¶m)); assert(status == napi_ok); - columbus::javascript::asg::expression::AssignmentProperty* source = dynamic_cast(obj->_nativeObj); + columbus::javascript::asg::structure::PropertyDefinition* source = dynamic_cast(obj->_nativeObj); columbus::javascript::asg::base::Positioned* target = dynamic_cast(param->_nativeObj); if(source == nullptr){ - status = napi_throw_error(env, nullptr, "Cannot cast expression::AssignmentProperty" ); + status = napi_throw_error(env, nullptr, "Cannot cast structure::PropertyDefinition" ); } if(target == nullptr){ status = napi_throw_error(env, nullptr, "Cannot cast base::Positioned" ); } - source->setValue(target); + source->setKey(target); return nullptr; } -napi_value AssignmentPropertyWrapper::setKey(napi_env env, napi_callback_info info){ +napi_value PropertyDefinitionWrapper::setValue(napi_env env, napi_callback_info info){ napi_status status; napi_value jsthis; size_t argc = 1; @@ -116,7 +114,7 @@ napi_value AssignmentPropertyWrapper::setKey(napi_env env, napi_callback_info in return nullptr; } - AssignmentPropertyWrapper* obj; + PropertyDefinitionWrapper* obj; BaseWrapper* param; status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); assert(status == napi_ok); @@ -124,20 +122,20 @@ napi_value AssignmentPropertyWrapper::setKey(napi_env env, napi_callback_info in status = napi_unwrap(env, args[0], reinterpret_cast(¶m)); assert(status == napi_ok); - columbus::javascript::asg::expression::AssignmentProperty* source = dynamic_cast(obj->_nativeObj); + columbus::javascript::asg::structure::PropertyDefinition* source = dynamic_cast(obj->_nativeObj); columbus::javascript::asg::expression::Expression* target = dynamic_cast(param->_nativeObj); if(source == nullptr){ - status = napi_throw_error(env, nullptr, "Cannot cast expression::AssignmentProperty" ); + status = napi_throw_error(env, nullptr, "Cannot cast structure::PropertyDefinition" ); } if(target == nullptr){ status = napi_throw_error(env, nullptr, "Cannot cast expression::Expression" ); } - source->setKey(target); + source->setValue(target); return nullptr; } -napi_value AssignmentPropertyWrapper::addComments(napi_env env, napi_callback_info info){ +napi_value PropertyDefinitionWrapper::addComments(napi_env env, napi_callback_info info){ napi_status status; napi_value jsthis; size_t argc = 1; @@ -150,7 +148,7 @@ napi_value AssignmentPropertyWrapper::addComments(napi_env env, napi_callback_in return nullptr; } - AssignmentPropertyWrapper* obj; + PropertyDefinitionWrapper* obj; BaseWrapper* param; status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); assert(status == napi_ok); @@ -158,11 +156,11 @@ napi_value AssignmentPropertyWrapper::addComments(napi_env env, napi_callback_in status = napi_unwrap(env, args[0], reinterpret_cast(¶m)); assert(status == napi_ok); - columbus::javascript::asg::expression::AssignmentProperty* source = dynamic_cast(obj->_nativeObj); + columbus::javascript::asg::structure::PropertyDefinition* source = dynamic_cast(obj->_nativeObj); columbus::javascript::asg::base::Comment* target = dynamic_cast(param->_nativeObj); if(source == nullptr){ - status = napi_throw_error(env, nullptr, "Cannot cast expression::AssignmentProperty" ); + status = napi_throw_error(env, nullptr, "Cannot cast structure::PropertyDefinition" ); } if(target == nullptr){ status = napi_throw_error(env, nullptr, "Cannot cast base::Comment" ); @@ -171,83 +169,7 @@ napi_value AssignmentPropertyWrapper::addComments(napi_env env, napi_callback_in source->addComments(target); return nullptr; } -napi_value AssignmentPropertyWrapper::setKind(napi_env env, napi_callback_info info){ - napi_status status; - napi_value jsthis; - size_t argc = 1; - napi_value args[1]; - status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); - assert(status == napi_ok); - - if (argc != 1) { - napi_throw_type_error(env, nullptr, "Wrong number of arguments."); - return nullptr; - } - - AssignmentPropertyWrapper* obj; - status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); - assert(status == napi_ok); - - napi_valuetype paramtype; - status = napi_typeof(env, args[0], ¶mtype); - assert(status == napi_ok); - - if(paramtype != napi_string){ - napi_throw_type_error(env, nullptr, "Argument should be a string!"); - return nullptr; - } - - char buffer[1024]; - size_t buffer_size = 1024, result_size = 0; - status = napi_get_value_string_utf8(env, args[0], buffer, buffer_size, &result_size); - assert(status == napi_ok); - - std::string param(buffer); - - if( param == "pkInit" ){ - dynamic_cast(obj->_nativeObj)->setKind( pkInit ); - } - if( param == "pkGet" ){ - dynamic_cast(obj->_nativeObj)->setKind( pkGet ); - } - if( param == "pkSet" ){ - dynamic_cast(obj->_nativeObj)->setKind( pkSet ); - } - return nullptr; -} -napi_value AssignmentPropertyWrapper::setMethod(napi_env env, napi_callback_info info){ - napi_status status; - napi_value jsthis; - size_t argc = 1; - napi_value args[1]; - status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr); - assert(status == napi_ok); - - if (argc != 1) { - napi_throw_type_error(env, nullptr, "Wrong number of arguments."); - return nullptr; - } - - AssignmentPropertyWrapper* obj; - status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); - assert(status == napi_ok); - - napi_valuetype paramtype; - status = napi_typeof(env, args[0], ¶mtype); - assert(status == napi_ok); - - if(paramtype != napi_boolean){ - napi_throw_type_error(env, nullptr, "Argument should be a boolean!"); - return nullptr; - } - - bool b; - status = napi_get_value_bool(env, args[0], &b); - assert(status == napi_ok); - dynamic_cast(obj->_nativeObj)->setMethod( b ); - return nullptr; -} -napi_value AssignmentPropertyWrapper::setShorthand(napi_env env, napi_callback_info info){ +napi_value PropertyDefinitionWrapper::setComputed(napi_env env, napi_callback_info info){ napi_status status; napi_value jsthis; size_t argc = 1; @@ -260,7 +182,7 @@ napi_value AssignmentPropertyWrapper::setShorthand(napi_env env, napi_callback_i return nullptr; } - AssignmentPropertyWrapper* obj; + PropertyDefinitionWrapper* obj; status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); assert(status == napi_ok); @@ -276,10 +198,10 @@ napi_value AssignmentPropertyWrapper::setShorthand(napi_env env, napi_callback_i bool b; status = napi_get_value_bool(env, args[0], &b); assert(status == napi_ok); - dynamic_cast(obj->_nativeObj)->setShorthand( b ); + dynamic_cast(obj->_nativeObj)->setComputed( b ); return nullptr; } -napi_value AssignmentPropertyWrapper::setComputed(napi_env env, napi_callback_info info){ +napi_value PropertyDefinitionWrapper::setStatic(napi_env env, napi_callback_info info){ napi_status status; napi_value jsthis; size_t argc = 1; @@ -292,7 +214,7 @@ napi_value AssignmentPropertyWrapper::setComputed(napi_env env, napi_callback_in return nullptr; } - AssignmentPropertyWrapper* obj; + PropertyDefinitionWrapper* obj; status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); assert(status == napi_ok); @@ -308,10 +230,10 @@ napi_value AssignmentPropertyWrapper::setComputed(napi_env env, napi_callback_in bool b; status = napi_get_value_bool(env, args[0], &b); assert(status == napi_ok); - dynamic_cast(obj->_nativeObj)->setComputed( b ); + dynamic_cast(obj->_nativeObj)->setStatic( b ); return nullptr; } -napi_value AssignmentPropertyWrapper::setPath(napi_env env, napi_callback_info info) { +napi_value PropertyDefinitionWrapper::setPath(napi_env env, napi_callback_info info) { napi_status status; napi_value jsthis; size_t argc = 1; @@ -324,7 +246,7 @@ napi_value AssignmentPropertyWrapper::setPath(napi_env env, napi_callback_info i return nullptr; } - AssignmentPropertyWrapper* obj; + PropertyDefinitionWrapper* obj; napi_valuetype valuetype; status = napi_typeof(env, args[0], &valuetype); assert(status == napi_ok); @@ -350,7 +272,7 @@ napi_value AssignmentPropertyWrapper::setPath(napi_env env, napi_callback_info i } -napi_value AssignmentPropertyWrapper::setPosition(napi_env env, napi_callback_info info) { +napi_value PropertyDefinitionWrapper::setPosition(napi_env env, napi_callback_info info) { napi_status status; napi_value jsthis; size_t argc = 8; @@ -363,7 +285,7 @@ napi_value AssignmentPropertyWrapper::setPosition(napi_env env, napi_callback_in return nullptr; } - AssignmentPropertyWrapper* obj; + PropertyDefinitionWrapper* obj; napi_valuetype valuetype[8]; int32_t position[8]; bool hasProp[8]; diff --git a/lib/javascript/inc/Common.h b/lib/javascript/inc/Common.h index f8c2d67..ab624b4 100644 --- a/lib/javascript/inc/Common.h +++ b/lib/javascript/inc/Common.h @@ -161,18 +161,18 @@ namespace columbus { namespace javascript { namespace asg { bool getIsAssignmentExpression(const base::Base& node); /** - * \brief Decides whether the node is expression::AssignmentProperty or not. + * \brief Decides whether the node is expression::AwaitExpression or not. * \param node [in] The node whose kind is examined. - * \return Returns true if the node is expression::AssignmentProperty. + * \return Returns true if the node is expression::AwaitExpression. */ - bool getIsAssignmentProperty(const base::Base& node); + bool getIsAwaitExpression(const base::Base& node); /** - * \brief Decides whether the node is expression::AwaitExpression or not. + * \brief Decides whether the node is expression::BigIntLiteral or not. * \param node [in] The node whose kind is examined. - * \return Returns true if the node is expression::AwaitExpression. + * \return Returns true if the node is expression::BigIntLiteral. */ - bool getIsAwaitExpression(const base::Base& node); + bool getIsBigIntLiteral(const base::Base& node); /** * \brief Decides whether the node is expression::BinaryExpression or not. @@ -195,6 +195,20 @@ namespace columbus { namespace javascript { namespace asg { */ bool getIsCallExpression(const base::Base& node); + /** + * \brief Decides whether the node is expression::ChainElement or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::ChainElement. + */ + bool getIsChainElement(const base::Base& node); + + /** + * \brief Decides whether the node is expression::ChainExpression or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::ChainExpression. + */ + bool getIsChainExpression(const base::Base& node); + /** * \brief Decides whether the node is expression::ClassExpression or not. * \param node [in] The node whose kind is examined. @@ -230,6 +244,13 @@ namespace columbus { namespace javascript { namespace asg { */ bool getIsIdentifier(const base::Base& node); + /** + * \brief Decides whether the node is expression::ImportExpression or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::ImportExpression. + */ + bool getIsImportExpression(const base::Base& node); + /** * \brief Decides whether the node is expression::Literal or not. * \param node [in] The node whose kind is examined. @@ -286,6 +307,13 @@ namespace columbus { namespace javascript { namespace asg { */ bool getIsObjectExpression(const base::Base& node); + /** + * \brief Decides whether the node is expression::PrivateIdentifier or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::PrivateIdentifier. + */ + bool getIsPrivateIdentifier(const base::Base& node); + /** * \brief Decides whether the node is expression::Property or not. * \param node [in] The node whose kind is examined. @@ -629,6 +657,13 @@ namespace columbus { namespace javascript { namespace asg { */ bool getIsModuleSpecifier(const base::Base& node); + /** + * \brief Decides whether the node is structure::PropertyDefinition or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is structure::PropertyDefinition. + */ + bool getIsPropertyDefinition(const base::Base& node); + /** * \brief Decides whether the 'base' is one of the base kinds (transitive) of 'what'. * \param what [in] The examined node kind. diff --git a/lib/javascript/inc/Constant.h b/lib/javascript/inc/Constant.h index 2467f6c..84b25b8 100644 --- a/lib/javascript/inc/Constant.h +++ b/lib/javascript/inc/Constant.h @@ -32,12 +32,12 @@ namespace columbus { namespace javascript { namespace asg { /** * \brief The API version of the schema. */ - const std::string APIVersion = "0.2.3"; + const std::string APIVersion = "0.2.6"; /** * \brief The binary version of the schema. */ - const std::string BinaryVersion = "0.2.3"; + const std::string BinaryVersion = "0.2.6"; }}} diff --git a/lib/javascript/inc/Factory.h b/lib/javascript/inc/Factory.h index 6910ba5..9ef883c 100644 --- a/lib/javascript/inc/Factory.h +++ b/lib/javascript/inc/Factory.h @@ -258,8 +258,8 @@ namespace columbus { namespace javascript { namespace asg { const_iterator(const const_iterator& otherit) :containerIt (otherit.containerIt),fact(otherit.fact){} const_iterator& operator++() {containerIt++; while (containerIt != fact->container.end() && ((*containerIt == NULL) || fact->getIsFiltered(*containerIt))) containerIt++; return *this;} const_iterator operator++(int) {const_iterator tmp(*this); operator++(); return tmp;} - bool operator==(const const_iterator& rhs) {return containerIt==rhs.containerIt;} - bool operator!=(const const_iterator& rhs) {return containerIt!=rhs.containerIt;} + bool operator==(const const_iterator& rhs) const {return containerIt==rhs.containerIt;} + bool operator!=(const const_iterator& rhs) const {return containerIt!=rhs.containerIt;} const base::Base* operator*() {return *containerIt;} friend class Factory; }; @@ -568,13 +568,13 @@ namespace columbus { namespace javascript { namespace asg { * \brief Creates a new node, insert it into the container and return with it. * \return Reference to the new node. */ - expression::AssignmentProperty* createAssignmentPropertyNode(); + expression::AwaitExpression* createAwaitExpressionNode(); /** * \brief Creates a new node, insert it into the container and return with it. * \return Reference to the new node. */ - expression::AwaitExpression* createAwaitExpressionNode(); + expression::BigIntLiteral* createBigIntLiteralNode(); /** * \brief Creates a new node, insert it into the container and return with it. @@ -594,6 +594,18 @@ namespace columbus { namespace javascript { namespace asg { */ expression::CallExpression* createCallExpressionNode(); + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::ChainElement* createChainElementNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::ChainExpression* createChainExpressionNode(); + /** * \brief Creates a new node, insert it into the container and return with it. * \return Reference to the new node. @@ -618,6 +630,12 @@ namespace columbus { namespace javascript { namespace asg { */ expression::Identifier* createIdentifierNode(); + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::ImportExpression* createImportExpressionNode(); + /** * \brief Creates a new node, insert it into the container and return with it. * \return Reference to the new node. @@ -660,6 +678,12 @@ namespace columbus { namespace javascript { namespace asg { */ expression::ObjectExpression* createObjectExpressionNode(); + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::PrivateIdentifier* createPrivateIdentifierNode(); + /** * \brief Creates a new node, insert it into the container and return with it. * \return Reference to the new node. @@ -924,6 +948,12 @@ namespace columbus { namespace javascript { namespace asg { */ structure::MethodDefinition* createMethodDefinitionNode(); + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + structure::PropertyDefinition* createPropertyDefinitionNode(); + /** * \brief Flush the node Sizes to the default out */ @@ -1032,16 +1062,19 @@ namespace columbus { namespace javascript { namespace asg { friend class expression::ArrayExpression; friend class expression::ArrowFunctionExpression; friend class expression::AssignmentExpression; - friend class expression::AssignmentProperty; friend class expression::AwaitExpression; + friend class expression::BigIntLiteral; friend class expression::BinaryExpression; friend class expression::BooleanLiteral; friend class expression::CallExpression; + friend class expression::ChainElement; + friend class expression::ChainExpression; friend class expression::ClassExpression; friend class expression::ConditionalExpression; friend class expression::Expression; friend class expression::FunctionExpression; friend class expression::Identifier; + friend class expression::ImportExpression; friend class expression::Literal; friend class expression::LogicalExpression; friend class expression::MemberExpression; @@ -1050,6 +1083,7 @@ namespace columbus { namespace javascript { namespace asg { friend class expression::NullLiteral; friend class expression::NumberLiteral; friend class expression::ObjectExpression; + friend class expression::PrivateIdentifier; friend class expression::Property; friend class expression::RegExpLiteral; friend class expression::SequenceExpression; @@ -1099,6 +1133,7 @@ namespace columbus { namespace javascript { namespace asg { friend class structure::ImportSpecifier; friend class structure::MethodDefinition; friend class structure::ModuleSpecifier; + friend class structure::PropertyDefinition; }; // Factory diff --git a/lib/javascript/inc/Forwards.h b/lib/javascript/inc/Forwards.h index 2cf2888..161d595 100644 --- a/lib/javascript/inc/Forwards.h +++ b/lib/javascript/inc/Forwards.h @@ -74,16 +74,19 @@ namespace columbus { namespace javascript { namespace asg { class ArrayExpression; class ArrowFunctionExpression; class AssignmentExpression; - class AssignmentProperty; class AwaitExpression; + class BigIntLiteral; class BinaryExpression; class BooleanLiteral; class CallExpression; + class ChainElement; + class ChainExpression; class ClassExpression; class ConditionalExpression; class Expression; class FunctionExpression; class Identifier; + class ImportExpression; class Literal; class LogicalExpression; class MemberExpression; @@ -92,6 +95,7 @@ namespace columbus { namespace javascript { namespace asg { class NullLiteral; class NumberLiteral; class ObjectExpression; + class PrivateIdentifier; class Property; class RegExpLiteral; class SequenceExpression; @@ -147,6 +151,7 @@ namespace columbus { namespace javascript { namespace asg { class ImportSpecifier; class MethodDefinition; class ModuleSpecifier; + class PropertyDefinition; } diff --git a/lib/javascript/inc/ReverseEdges.h b/lib/javascript/inc/ReverseEdges.h index 8dd3069..cc4bf86 100644 --- a/lib/javascript/inc/ReverseEdges.h +++ b/lib/javascript/inc/ReverseEdges.h @@ -188,7 +188,7 @@ namespace columbus { namespace javascript { namespace asg { RevEdgesContainer reContainer; /** \internal \brief The possible edges by nodes. */ - static bool possibleEdges[86][95]; + static bool possibleEdges[91][100]; friend class Factory; friend class VisitorReverseEdges; @@ -212,16 +212,19 @@ namespace columbus { namespace javascript { namespace asg { friend class expression::ArrayExpression; friend class expression::ArrowFunctionExpression; friend class expression::AssignmentExpression; - friend class expression::AssignmentProperty; friend class expression::AwaitExpression; + friend class expression::BigIntLiteral; friend class expression::BinaryExpression; friend class expression::BooleanLiteral; friend class expression::CallExpression; + friend class expression::ChainElement; + friend class expression::ChainExpression; friend class expression::ClassExpression; friend class expression::ConditionalExpression; friend class expression::Expression; friend class expression::FunctionExpression; friend class expression::Identifier; + friend class expression::ImportExpression; friend class expression::Literal; friend class expression::LogicalExpression; friend class expression::MemberExpression; @@ -230,6 +233,7 @@ namespace columbus { namespace javascript { namespace asg { friend class expression::NullLiteral; friend class expression::NumberLiteral; friend class expression::ObjectExpression; + friend class expression::PrivateIdentifier; friend class expression::Property; friend class expression::RegExpLiteral; friend class expression::SequenceExpression; @@ -279,6 +283,7 @@ namespace columbus { namespace javascript { namespace asg { friend class structure::ImportSpecifier; friend class structure::MethodDefinition; friend class structure::ModuleSpecifier; + friend class structure::PropertyDefinition; }; // ReverseEdges diff --git a/lib/javascript/inc/Types.h b/lib/javascript/inc/Types.h index 98b702c..ee194a1 100644 --- a/lib/javascript/inc/Types.h +++ b/lib/javascript/inc/Types.h @@ -41,6 +41,9 @@ namespace columbus { namespace javascript { namespace asg { asoBitwiseXor, asoBitwiseAnd, asoExponentiation, + asoAnd, + asoOr, + asoNullishCoalescing, asoLAST }; @@ -92,6 +95,7 @@ namespace columbus { namespace javascript { namespace asg { enum LogicalOperator { looAnd, looOr, + looNullishCoalescing, looLAST }; @@ -153,16 +157,19 @@ namespace columbus { namespace javascript { namespace asg { ndkArrayExpression, ndkArrowFunctionExpression, ndkAssignmentExpression, - ndkAssignmentProperty, ndkAwaitExpression, + ndkBigIntLiteral, ndkBinaryExpression, ndkBooleanLiteral, ndkCallExpression, + ndkChainElement, + ndkChainExpression, ndkClassExpression, ndkConditionalExpression, ndkExpression, ndkFunctionExpression, ndkIdentifier, + ndkImportExpression, ndkLiteral, ndkLogicalExpression, ndkMemberExpression, @@ -171,6 +178,7 @@ namespace columbus { namespace javascript { namespace asg { ndkNullLiteral, ndkNumberLiteral, ndkObjectExpression, + ndkPrivateIdentifier, ndkProperty, ndkRegExpLiteral, ndkSequenceExpression, @@ -220,6 +228,7 @@ namespace columbus { namespace javascript { namespace asg { ndkImportSpecifier, ndkMethodDefinition, ndkModuleSpecifier, + ndkPropertyDefinition, ndkLAST }; @@ -228,6 +237,7 @@ namespace columbus { namespace javascript { namespace asg { edkProgram_HasBody, edkSystem_HasPrograms, edkExportAllDeclaration_HasSource, + edkExportAllDeclaration_HasExported, edkExportDefaultDeclaration_HasDeclaration, edkExportNamedDeclaration_HasDeclaration, edkExportNamedDeclaration_HasSpecifiers, @@ -246,10 +256,12 @@ namespace columbus { namespace javascript { namespace asg { edkCallExpression_HasCallee, edkCallExpression_HasArguments, edkCallExpression_Calls, + edkChainExpression_HasExpression, edkConditionalExpression_HasAlternate, edkConditionalExpression_HasConsequent, edkConditionalExpression_HasTest, edkIdentifier_RefersTo, + edkImportExpression_HasSource, edkLogicalExpression_HasLeft, edkLogicalExpression_HasRight, edkMemberExpression_HasProperty, @@ -319,6 +331,8 @@ namespace columbus { namespace javascript { namespace asg { edkMethodDefinition_HasKey, edkMethodDefinition_HasValue, edkModuleSpecifier_HasLocal, + edkPropertyDefinition_HasKey, + edkPropertyDefinition_HasValue, edkLAST }; diff --git a/lib/javascript/inc/algorithms/AlgorithmPreorder.h b/lib/javascript/inc/algorithms/AlgorithmPreorder.h index f374b10..c1a8ed9 100644 --- a/lib/javascript/inc/algorithms/AlgorithmPreorder.h +++ b/lib/javascript/inc/algorithms/AlgorithmPreorder.h @@ -238,13 +238,13 @@ namespace columbus { namespace javascript { namespace asg { * \internal * \brief The node call back the this function that achive the preorder */ - virtual void visit(const expression::AssignmentProperty& node , bool callVirtualBase = true); + virtual void visit(const expression::AwaitExpression& node , bool callVirtualBase = true); /** * \internal * \brief The node call back the this function that achive the preorder */ - virtual void visit(const expression::AwaitExpression& node , bool callVirtualBase = true); + virtual void visit(const expression::BigIntLiteral& node , bool callVirtualBase = true); /** * \internal @@ -264,6 +264,18 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visit(const expression::CallExpression& node , bool callVirtualBase = true); + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::ChainElement& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::ChainExpression& node , bool callVirtualBase = true); + /** * \internal * \brief The node call back the this function that achive the preorder @@ -288,6 +300,12 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visit(const expression::Identifier& node , bool callVirtualBase = true); + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::ImportExpression& node , bool callVirtualBase = true); + /** * \internal * \brief The node call back the this function that achive the preorder @@ -330,6 +348,12 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visit(const expression::ObjectExpression& node , bool callVirtualBase = true); + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::PrivateIdentifier& node , bool callVirtualBase = true); + /** * \internal * \brief The node call back the this function that achive the preorder @@ -594,6 +618,12 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visit(const structure::MethodDefinition& node , bool callVirtualBase = true); + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const structure::PropertyDefinition& node , bool callVirtualBase = true); + /** \internal \brief End The visitor functions owerloades */ protected: /** @@ -754,7 +784,7 @@ namespace columbus { namespace javascript { namespace asg { * \param node [in] The node with own type * \param callVirtualBase [in] This paramater is don't used just api copatibility used. */ - virtual void visitAllEdges(const expression::AssignmentProperty& node , bool callVirtualBase = true); + virtual void visitAllEdges(const expression::AwaitExpression& node , bool callVirtualBase = true); /** * \internal @@ -762,7 +792,7 @@ namespace columbus { namespace javascript { namespace asg { * \param node [in] The node with own type * \param callVirtualBase [in] This paramater is don't used just api copatibility used. */ - virtual void visitAllEdges(const expression::AwaitExpression& node , bool callVirtualBase = true); + virtual void visitAllEdges(const expression::BigIntLiteral& node , bool callVirtualBase = true); /** * \internal @@ -788,6 +818,22 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitAllEdges(const expression::CallExpression& node , bool callVirtualBase = true); + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::ChainElement& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::ChainExpression& node , bool callVirtualBase = true); + /** * \internal * \brief It call the traversal for the edges @@ -828,6 +874,14 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitAllEdges(const expression::Identifier& node , bool callVirtualBase = true); + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::ImportExpression& node , bool callVirtualBase = true); + /** * \internal * \brief It call the traversal for the edges @@ -892,6 +946,14 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitAllEdges(const expression::ObjectExpression& node , bool callVirtualBase = true); + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::PrivateIdentifier& node , bool callVirtualBase = true); + /** * \internal * \brief It call the traversal for the edges @@ -1284,6 +1346,14 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitAllEdges(const structure::ModuleSpecifier& node , bool callVirtualBase = true); + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const structure::PropertyDefinition& node , bool callVirtualBase = true); + /** * \internal * \brief Starts a preorder traversal. @@ -1335,7 +1405,7 @@ namespace columbus { namespace javascript { namespace asg { Factory* fact; - bool traversaldCrossEdges[95]; + bool traversaldCrossEdges[100]; }; // AlgorithmPreorder diff --git a/lib/javascript/inc/declaration/ExportAllDeclaration.h b/lib/javascript/inc/declaration/ExportAllDeclaration.h index 1e03c09..2d0f7d6 100644 --- a/lib/javascript/inc/declaration/ExportAllDeclaration.h +++ b/lib/javascript/inc/declaration/ExportAllDeclaration.h @@ -39,6 +39,7 @@ namespace declaration { * * Edges: * - hasSource (expression::Literal, single) : (missing) + * - hasExported (expression::Identifier, single) : (missing) */ class ExportAllDeclaration : public Declaration { protected: @@ -109,6 +110,12 @@ namespace declaration { */ expression::Literal* getSource() const; + /** + * \brief Gives back the pointer of the node the hasExported edge points to. + * \return Returns the end point of the hasExported edge. + */ + expression::Identifier* getExported() const; + // ---------- Edge setter function(s) ---------- @@ -129,6 +136,23 @@ namespace declaration { */ void removeSource(); + /** + * \brief Sets the hasExported edge. + * \param id [in] The new end point of the hasExported edge. + */ + void setExported(NodeId id); + + /** + * \brief Sets the hasExported edge. + * \param node [in] The new end point of the hasExported edge. + */ + void setExported(expression::Identifier *node); + + /** + * \brief remove the hasExported edge. + */ + void removeExported(); + protected: // ---------- Edges ---------- @@ -136,6 +160,9 @@ namespace declaration { /** \internal \brief The id of the node the hasSource edge points to. */ NodeId m_hasSource; + /** \internal \brief The id of the node the hasExported edge points to. */ + NodeId m_hasExported; + public: // ---------- Accept fundtions for Visitor ---------- diff --git a/lib/javascript/inc/expression/BigIntLiteral.h b/lib/javascript/inc/expression/BigIntLiteral.h new file mode 100644 index 0000000..335f948 --- /dev/null +++ b/lib/javascript/inc/expression/BigIntLiteral.h @@ -0,0 +1,203 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _JAVASCRIPT_BigIntLiteral_H_ +#define _JAVASCRIPT_BigIntLiteral_H_ + +#include "javascript/inc/javascript.h" + +/** +* \file BigIntLiteral.h +* \brief Contains declaration of the expression::BigIntLiteral class. +* \brief The it get atributes from + * \brief base::Positioned +*/ + +namespace columbus { namespace javascript { namespace asg { +namespace expression { + + /** + * \brief BigIntLiteral class, which represents the expression::BigIntLiteral node. + * (missing) + * + * Attributes: + * - bigint (String) : (missing) + */ + class BigIntLiteral : public Literal { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + BigIntLiteral(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~BigIntLiteral(); + + private: + /** + * \brief This function always throws a JavascriptException due to copying is not allowed! + */ + BigIntLiteral & operator=(const BigIntLiteral&); + + /** + * \brief This function always throws a JavascriptException due to copying is not allowed! + */ + BigIntLiteral(const BigIntLiteral&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the bigint of the node. + * \return Returns with the bigint. + */ + const std::string& getBigint() const; + + /** + * \brief Gives back the Key of bigint of the node. + * \return Returns with the Key of the bigint. + */ + Key getBigintKey() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the bigint of the node. + * \param bigint [in] The new value of the bigint. + */ + void setBigint(const std::string& _bigint); + + /** + * \internal + * \brief Sets the bigint of the node. + * \param bigint [in] The new Key of the bigint. + */ + void setBigintKey(Key _bigint); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The Key of the `bigint`. */ + Key m_bigint; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class javascript::asg::Factory; + friend class javascript::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/javascript/inc/expression/BinaryExpression.h b/lib/javascript/inc/expression/BinaryExpression.h index 356ecff..e47ba47 100644 --- a/lib/javascript/inc/expression/BinaryExpression.h +++ b/lib/javascript/inc/expression/BinaryExpression.h @@ -41,7 +41,7 @@ namespace expression { * - operator (BinaryOperator) : (missing) * * Edges: - * - hasLeft (expression::Expression, single) : (missing) + * - hasLeft (base::Positioned, single) : (missing) * - hasRight (expression::Expression, single) : (missing) */ class BinaryExpression : public Expression { @@ -137,7 +137,7 @@ namespace expression { * \brief Gives back the pointer of the node the hasLeft edge points to. * \return Returns the end point of the hasLeft edge. */ - expression::Expression* getLeft() const; + base::Positioned* getLeft() const; /** * \brief Gives back the pointer of the node the hasRight edge points to. @@ -158,7 +158,7 @@ namespace expression { * \brief Sets the hasLeft edge. * \param node [in] The new end point of the hasLeft edge. */ - void setLeft(Expression *node); + void setLeft(base::Positioned *node); /** * \brief remove the hasLeft edge. diff --git a/lib/javascript/inc/expression/CallExpression.h b/lib/javascript/inc/expression/CallExpression.h index 204ddc5..19bd535 100644 --- a/lib/javascript/inc/expression/CallExpression.h +++ b/lib/javascript/inc/expression/CallExpression.h @@ -42,7 +42,7 @@ namespace expression { * - hasArguments (base::Positioned, multiple) : (missing) * - calls (statement::Function, multiple) : (missing) */ - class CallExpression : public Expression { + class CallExpression : public Expression, public ChainElement { protected: /** * \internal diff --git a/lib/javascript/inc/expression/ChainElement.h b/lib/javascript/inc/expression/ChainElement.h new file mode 100644 index 0000000..aebf298 --- /dev/null +++ b/lib/javascript/inc/expression/ChainElement.h @@ -0,0 +1,189 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _JAVASCRIPT_ChainElement_H_ +#define _JAVASCRIPT_ChainElement_H_ + +#include "javascript/inc/javascript.h" + +/** +* \file ChainElement.h +* \brief Contains declaration of the expression::ChainElement class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace javascript { namespace asg { +namespace expression { + + /** + * \brief ChainElement class, which represents the expression::ChainElement node. + * (missing) + * + * Attributes: + * - optional (boolean) : (missing) + */ + class ChainElement : public virtual base::Positioned { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + ChainElement(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~ChainElement(); + + private: + /** + * \brief This function always throws a JavascriptException due to copying is not allowed! + */ + ChainElement & operator=(const ChainElement&); + + /** + * \brief This function always throws a JavascriptException due to copying is not allowed! + */ + ChainElement(const ChainElement&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the optional of the node. + * \return Returns with the optional. + */ + bool getOptional() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the optional of the node. + * \param optional [in] The new value of the optional. + */ + void setOptional(bool _optional); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The value of the `optional`. */ + bool m_optional : 1; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class javascript::asg::Factory; + friend class javascript::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/javascript/inc/expression/ChainExpression.h b/lib/javascript/inc/expression/ChainExpression.h new file mode 100644 index 0000000..9837392 --- /dev/null +++ b/lib/javascript/inc/expression/ChainExpression.h @@ -0,0 +1,201 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _JAVASCRIPT_ChainExpression_H_ +#define _JAVASCRIPT_ChainExpression_H_ + +#include "javascript/inc/javascript.h" + +/** +* \file ChainExpression.h +* \brief Contains declaration of the expression::ChainExpression class. +* \brief The it get atributes from + * \brief base::Positioned +*/ + +namespace columbus { namespace javascript { namespace asg { +namespace expression { + + /** + * \brief ChainExpression class, which represents the expression::ChainExpression node. + * (missing) + * + * Edges: + * - hasExpression (expression::ChainElement, single) : (missing) + */ + class ChainExpression : public Expression { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + ChainExpression(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~ChainExpression(); + + private: + /** + * \brief This function always throws a JavascriptException due to copying is not allowed! + */ + ChainExpression & operator=(const ChainExpression&); + + /** + * \brief This function always throws a JavascriptException due to copying is not allowed! + */ + ChainExpression(const ChainExpression&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasExpression edge points to. + * \return Returns the end point of the hasExpression edge. + */ + expression::ChainElement* getExpression() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasExpression edge. + * \param id [in] The new end point of the hasExpression edge. + */ + void setExpression(NodeId id); + + /** + * \brief Sets the hasExpression edge. + * \param node [in] The new end point of the hasExpression edge. + */ + void setExpression(ChainElement *node); + + /** + * \brief remove the hasExpression edge. + */ + void removeExpression(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasExpression edge points to. */ + NodeId m_hasExpression; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class javascript::asg::Factory; + friend class javascript::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/javascript/inc/expression/ImportExpression.h b/lib/javascript/inc/expression/ImportExpression.h new file mode 100644 index 0000000..6b54224 --- /dev/null +++ b/lib/javascript/inc/expression/ImportExpression.h @@ -0,0 +1,201 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _JAVASCRIPT_ImportExpression_H_ +#define _JAVASCRIPT_ImportExpression_H_ + +#include "javascript/inc/javascript.h" + +/** +* \file ImportExpression.h +* \brief Contains declaration of the expression::ImportExpression class. +* \brief The it get atributes from + * \brief base::Positioned +*/ + +namespace columbus { namespace javascript { namespace asg { +namespace expression { + + /** + * \brief ImportExpression class, which represents the expression::ImportExpression node. + * (missing) + * + * Edges: + * - hasSource (expression::Expression, single) : (missing) + */ + class ImportExpression : public Expression { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + ImportExpression(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~ImportExpression(); + + private: + /** + * \brief This function always throws a JavascriptException due to copying is not allowed! + */ + ImportExpression & operator=(const ImportExpression&); + + /** + * \brief This function always throws a JavascriptException due to copying is not allowed! + */ + ImportExpression(const ImportExpression&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasSource edge points to. + * \return Returns the end point of the hasSource edge. + */ + expression::Expression* getSource() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasSource edge. + * \param id [in] The new end point of the hasSource edge. + */ + void setSource(NodeId id); + + /** + * \brief Sets the hasSource edge. + * \param node [in] The new end point of the hasSource edge. + */ + void setSource(Expression *node); + + /** + * \brief remove the hasSource edge. + */ + void removeSource(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasSource edge points to. */ + NodeId m_hasSource; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class javascript::asg::Factory; + friend class javascript::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/javascript/inc/expression/MemberExpression.h b/lib/javascript/inc/expression/MemberExpression.h index e39c284..41c788d 100644 --- a/lib/javascript/inc/expression/MemberExpression.h +++ b/lib/javascript/inc/expression/MemberExpression.h @@ -41,10 +41,10 @@ namespace expression { * - computed (boolean) : (missing) * * Edges: - * - hasProperty (expression::Expression, single) : (missing) + * - hasProperty (base::Positioned, single) : (missing) * - hasObject (base::Positioned, single) : (missing) */ - class MemberExpression : public Expression, public statement::Pattern { + class MemberExpression : public Expression, public statement::Pattern, public ChainElement { protected: /** * \internal @@ -137,7 +137,7 @@ namespace expression { * \brief Gives back the pointer of the node the hasProperty edge points to. * \return Returns the end point of the hasProperty edge. */ - expression::Expression* getProperty() const; + base::Positioned* getProperty() const; /** * \brief Gives back the pointer of the node the hasObject edge points to. @@ -158,7 +158,7 @@ namespace expression { * \brief Sets the hasProperty edge. * \param node [in] The new end point of the hasProperty edge. */ - void setProperty(Expression *node); + void setProperty(base::Positioned *node); /** * \brief remove the hasProperty edge. diff --git a/lib/javascript/inc/expression/AssignmentProperty.h b/lib/javascript/inc/expression/PrivateIdentifier.h similarity index 88% rename from lib/javascript/inc/expression/AssignmentProperty.h rename to lib/javascript/inc/expression/PrivateIdentifier.h index 6401122..fd31d99 100644 --- a/lib/javascript/inc/expression/AssignmentProperty.h +++ b/lib/javascript/inc/expression/PrivateIdentifier.h @@ -18,14 +18,14 @@ * limitations under the Licence. */ -#ifndef _JAVASCRIPT_AssignmentProperty_H_ -#define _JAVASCRIPT_AssignmentProperty_H_ +#ifndef _JAVASCRIPT_PrivateIdentifier_H_ +#define _JAVASCRIPT_PrivateIdentifier_H_ #include "javascript/inc/javascript.h" /** -* \file AssignmentProperty.h -* \brief Contains declaration of the expression::AssignmentProperty class. +* \file PrivateIdentifier.h +* \brief Contains declaration of the expression::PrivateIdentifier class. * \brief The it get atributes from */ @@ -33,10 +33,10 @@ namespace columbus { namespace javascript { namespace asg { namespace expression { /** - * \brief AssignmentProperty class, which represents the expression::AssignmentProperty node. + * \brief PrivateIdentifier class, which represents the expression::PrivateIdentifier node. * (missing) */ - class AssignmentProperty : public Property { + class PrivateIdentifier : public virtual base::Positioned, public base::Named { protected: /** * \internal @@ -44,24 +44,24 @@ namespace expression { * \param nodeId [in] The id of the node. * \param factory [in] Poiter to the Factory the node belongs to. */ - AssignmentProperty(NodeId nodeId, Factory *factory); + PrivateIdentifier(NodeId nodeId, Factory *factory); /** * \internal * \brief Non-public destructor, only factory can destroy nodes. */ - virtual ~AssignmentProperty(); + virtual ~PrivateIdentifier(); private: /** * \brief This function always throws a JavascriptException due to copying is not allowed! */ - AssignmentProperty & operator=(const AssignmentProperty&); + PrivateIdentifier & operator=(const PrivateIdentifier&); /** * \brief This function always throws a JavascriptException due to copying is not allowed! */ - AssignmentProperty(const AssignmentProperty&); + PrivateIdentifier(const PrivateIdentifier&); public: /** diff --git a/lib/javascript/inc/javascript.h b/lib/javascript/inc/javascript.h index 3898315..0ddcf1c 100644 --- a/lib/javascript/inc/javascript.h +++ b/lib/javascript/inc/javascript.h @@ -25,30 +25,6 @@ * \file JAVASCRIPT.h * \brief Header can be used for precompiled header. */ -/*********** Options ************************* - * SchemaGeneratorc9e9f4bd0b - * IndentInNamespace = 1 - * IndentInClass = 1 - * IndentUnderPubProtPri = 1 - * UseShortRange = false - * ACommonGetIsForLeaf = true - * AlgPreorderSafeMode = true - * GenerateInOutForComment = true - * GenerateFilter = true - * GenerateReverseEdges = true - * GenerateAsgStat = true - * GenerateSpecFilterVisitor = false - * GenerateSpecXml = false - * GenerateDOT = false - * GenerateGraphml = true - * GenerateJSON = false - * GenerateSerialize = false - * GenerateParentEdge = true - * FactoryModes = - * APIVersion = 0.2.3 - * BinaryVersion = 0.2.3 - * CSIHeaderText = JavaScriptLanguage - *********************************************/ #include #include #include @@ -83,8 +59,10 @@ #include "base/Named.h" #include "declaration/ModuleDeclaration.h" #include "declaration/VariableDeclarator.h" +#include "expression/ChainElement.h" #include "expression/Expression.h" #include "expression/Literal.h" +#include "expression/PrivateIdentifier.h" #include "expression/Property.h" #include "expression/SpreadElement.h" #include "expression/Super.h" @@ -98,21 +76,24 @@ #include "structure/ClassBody.h" #include "structure/MethodDefinition.h" #include "structure/ModuleSpecifier.h" +#include "structure/PropertyDefinition.h" #include "base/Program.h" #include "expression/Identifier.h" #include "declaration/ExportNamedDeclaration.h" #include "declaration/ImportDeclaration.h" +#include "expression/CallExpression.h" +#include "expression/MemberExpression.h" #include "expression/ArrayExpression.h" #include "expression/ArrowFunctionExpression.h" #include "expression/AssignmentExpression.h" #include "expression/AwaitExpression.h" #include "expression/BinaryExpression.h" -#include "expression/CallExpression.h" +#include "expression/ChainExpression.h" #include "expression/ClassExpression.h" #include "expression/ConditionalExpression.h" #include "expression/FunctionExpression.h" +#include "expression/ImportExpression.h" #include "expression/LogicalExpression.h" -#include "expression/MemberExpression.h" #include "expression/MetaProperty.h" #include "expression/NewExpression.h" #include "expression/ObjectExpression.h" @@ -123,12 +104,12 @@ #include "expression/UnaryExpression.h" #include "expression/UpdateExpression.h" #include "expression/YieldExpression.h" +#include "expression/BigIntLiteral.h" #include "expression/BooleanLiteral.h" #include "expression/NullLiteral.h" #include "expression/NumberLiteral.h" #include "expression/RegExpLiteral.h" #include "expression/StringLiteral.h" -#include "expression/AssignmentProperty.h" #include "statement/ArrayPattern.h" #include "statement/AssignmentPattern.h" #include "statement/ObjectPattern.h" diff --git a/lib/javascript/inc/statement/ForOfStatement.h b/lib/javascript/inc/statement/ForOfStatement.h index e7656ff..c5e085c 100644 --- a/lib/javascript/inc/statement/ForOfStatement.h +++ b/lib/javascript/inc/statement/ForOfStatement.h @@ -38,7 +38,7 @@ namespace statement { * (missing) * * Attributes: - * - async (boolean) : (missing) + * - await (boolean) : (missing) */ class ForOfStatement : public ForInStatement { protected: @@ -83,27 +83,27 @@ namespace statement { // ---------- Attribute getter function(s) ---------- /** - * \brief Gives back the async of the node. - * \return Returns with the async. + * \brief Gives back the await of the node. + * \return Returns with the await. */ - bool getAsync() const; + bool getAwait() const; // ---------- Attribute setter function(s) ---------- /** * \internal - * \brief Sets the async of the node. - * \param async [in] The new value of the async. + * \brief Sets the await of the node. + * \param await [in] The new value of the await. */ - void setAsync(bool _async); + void setAwait(bool _await); protected: // ---------- Attribute(s) ---------- - /** \internal \brief The value of the `async`. */ - bool m_async : 1; + /** \internal \brief The value of the `await`. */ + bool m_await : 1; protected: /** diff --git a/lib/javascript/inc/structure/ClassBody.h b/lib/javascript/inc/structure/ClassBody.h index 61de06a..ef5a3e8 100644 --- a/lib/javascript/inc/structure/ClassBody.h +++ b/lib/javascript/inc/structure/ClassBody.h @@ -37,7 +37,7 @@ namespace structure { * (missing) * * Edges: - * - hasBody (structure::MethodDefinition, multiple) : (missing) + * - hasBody (base::Positioned, multiple) : (missing) */ class ClassBody : public base::Positioned { protected: @@ -106,13 +106,13 @@ namespace structure { * \brief Gives back iterator for the hasBody edges. * \return Returns an iterator for the hasBody edges. */ - ListIterator getBodyListIteratorBegin() const; + ListIterator getBodyListIteratorBegin() const; /** * \brief Gives back iterator for the hasBody edges. * \return Returns an iterator for the hasBody edges. */ - ListIterator getBodyListIteratorEnd() const; + ListIterator getBodyListIteratorEnd() const; /** * \brief Tells whether the node has hasBody edges or not. @@ -133,7 +133,7 @@ namespace structure { * \brief Adds a new hasBody edge to the node and inserts it after the other ones. * \param node [in] The end point of the new hasBody edge. */ - void addBody(const MethodDefinition *node); + void addBody(const base::Positioned *node); /** * \brief Adds a new hasBody edge to the node and inserts it after the other ones. @@ -151,14 +151,14 @@ namespace structure { * \brief Remove the hasBody edge from the node. * \param node [in] The end point of the hasBody edge. */ - void removeBody(MethodDefinition *node); + void removeBody(base::Positioned *node); protected: // ---------- Edges ---------- /** \internal \brief Container stores the id of the nodes the hasBody edge points to. */ - ListIterator::Container hasBodyContainer; + ListIterator::Container hasBodyContainer; public: diff --git a/lib/javascript/inc/structure/MethodDefinition.h b/lib/javascript/inc/structure/MethodDefinition.h index afd2d55..6b3649a 100644 --- a/lib/javascript/inc/structure/MethodDefinition.h +++ b/lib/javascript/inc/structure/MethodDefinition.h @@ -42,7 +42,7 @@ namespace structure { * - static (boolean) : (missing) * * Edges: - * - hasKey (expression::Expression, single) : (missing) + * - hasKey (base::Positioned, single) : (missing) * - hasValue (expression::FunctionExpression, single) : (missing) */ class MethodDefinition : public base::Positioned { @@ -170,7 +170,7 @@ namespace structure { * \brief Gives back the pointer of the node the hasKey edge points to. * \return Returns the end point of the hasKey edge. */ - expression::Expression* getKey() const; + base::Positioned* getKey() const; /** * \brief Gives back the pointer of the node the hasValue edge points to. @@ -191,7 +191,7 @@ namespace structure { * \brief Sets the hasKey edge. * \param node [in] The new end point of the hasKey edge. */ - void setKey(expression::Expression *node); + void setKey(base::Positioned *node); /** * \brief remove the hasKey edge. diff --git a/lib/javascript/inc/structure/PropertyDefinition.h b/lib/javascript/inc/structure/PropertyDefinition.h new file mode 100644 index 0000000..d6f5670 --- /dev/null +++ b/lib/javascript/inc/structure/PropertyDefinition.h @@ -0,0 +1,273 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _JAVASCRIPT_PropertyDefinition_H_ +#define _JAVASCRIPT_PropertyDefinition_H_ + +#include "javascript/inc/javascript.h" + +/** +* \file PropertyDefinition.h +* \brief Contains declaration of the structure::PropertyDefinition class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace javascript { namespace asg { +namespace structure { + + /** + * \brief PropertyDefinition class, which represents the structure::PropertyDefinition node. + * (missing) + * + * Attributes: + * - computed (boolean) : (missing) + * - static (boolean) : (missing) + * + * Edges: + * - hasKey (base::Positioned, single) : (missing) + * - hasValue (expression::Expression, single) : (missing) + */ + class PropertyDefinition : public base::Positioned { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + PropertyDefinition(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~PropertyDefinition(); + + private: + /** + * \brief This function always throws a JavascriptException due to copying is not allowed! + */ + PropertyDefinition & operator=(const PropertyDefinition&); + + /** + * \brief This function always throws a JavascriptException due to copying is not allowed! + */ + PropertyDefinition(const PropertyDefinition&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the computed of the node. + * \return Returns with the computed. + */ + bool getComputed() const; + + /** + * \brief Gives back the static of the node. + * \return Returns with the static. + */ + bool getStatic() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the computed of the node. + * \param computed [in] The new value of the computed. + */ + void setComputed(bool _computed); + + /** + * \internal + * \brief Sets the static of the node. + * \param static [in] The new value of the static. + */ + void setStatic(bool _static); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The value of the `computed`. */ + bool m_computed : 1; + + /** \internal \brief The value of the `static`. */ + bool m_static : 1; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasKey edge points to. + * \return Returns the end point of the hasKey edge. + */ + base::Positioned* getKey() const; + + /** + * \brief Gives back the pointer of the node the hasValue edge points to. + * \return Returns the end point of the hasValue edge. + */ + expression::Expression* getValue() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasKey edge. + * \param id [in] The new end point of the hasKey edge. + */ + void setKey(NodeId id); + + /** + * \brief Sets the hasKey edge. + * \param node [in] The new end point of the hasKey edge. + */ + void setKey(base::Positioned *node); + + /** + * \brief remove the hasKey edge. + */ + void removeKey(); + + /** + * \brief Sets the hasValue edge. + * \param id [in] The new end point of the hasValue edge. + */ + void setValue(NodeId id); + + /** + * \brief Sets the hasValue edge. + * \param node [in] The new end point of the hasValue edge. + */ + void setValue(expression::Expression *node); + + /** + * \brief remove the hasValue edge. + */ + void removeValue(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasKey edge points to. */ + NodeId m_hasKey; + + /** \internal \brief The id of the node the hasValue edge points to. */ + NodeId m_hasValue; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class javascript::asg::Factory; + friend class javascript::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/javascript/inc/visitors/Visitor.h b/lib/javascript/inc/visitors/Visitor.h index 585ad68..648c752 100644 --- a/lib/javascript/inc/visitors/Visitor.h +++ b/lib/javascript/inc/visitors/Visitor.h @@ -251,28 +251,28 @@ namespace columbus { namespace javascript { namespace asg { virtual void visitEnd(const expression::AssignmentExpression& node , bool callVirtualBase = true); /** - * \brief Visitor which is called at the beginning of the expression::AssignmentProperty node visiting. + * \brief Visitor which is called at the beginning of the expression::AwaitExpression node visiting. * \param node [in] The node which is visited. */ - virtual void visit(const expression::AssignmentProperty& node , bool callVirtualBase = true); + virtual void visit(const expression::AwaitExpression& node , bool callVirtualBase = true); /** - * \brief Visitor which is called at the end of the expression::AssignmentProperty node visiting. + * \brief Visitor which is called at the end of the expression::AwaitExpression node visiting. * \param node [in] The node which is visited. */ - virtual void visitEnd(const expression::AssignmentProperty& node , bool callVirtualBase = true); + virtual void visitEnd(const expression::AwaitExpression& node , bool callVirtualBase = true); /** - * \brief Visitor which is called at the beginning of the expression::AwaitExpression node visiting. + * \brief Visitor which is called at the beginning of the expression::BigIntLiteral node visiting. * \param node [in] The node which is visited. */ - virtual void visit(const expression::AwaitExpression& node , bool callVirtualBase = true); + virtual void visit(const expression::BigIntLiteral& node , bool callVirtualBase = true); /** - * \brief Visitor which is called at the end of the expression::AwaitExpression node visiting. + * \brief Visitor which is called at the end of the expression::BigIntLiteral node visiting. * \param node [in] The node which is visited. */ - virtual void visitEnd(const expression::AwaitExpression& node , bool callVirtualBase = true); + virtual void visitEnd(const expression::BigIntLiteral& node , bool callVirtualBase = true); /** * \brief Visitor which is called at the beginning of the expression::BinaryExpression node visiting. @@ -310,6 +310,30 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEnd(const expression::CallExpression& node , bool callVirtualBase = true); + /** + * \brief Visitor which is called at the beginning of the expression::ChainElement node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::ChainElement& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::ChainElement node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ChainElement& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::ChainExpression node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::ChainExpression& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::ChainExpression node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ChainExpression& node , bool callVirtualBase = true); + /** * \brief Visitor which is called at the beginning of the expression::ClassExpression node visiting. * \param node [in] The node which is visited. @@ -358,6 +382,18 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEnd(const expression::Identifier& node , bool callVirtualBase = true); + /** + * \brief Visitor which is called at the beginning of the expression::ImportExpression node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::ImportExpression& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::ImportExpression node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ImportExpression& node , bool callVirtualBase = true); + /** * \brief Visitor which is called at the beginning of the expression::LogicalExpression node visiting. * \param node [in] The node which is visited. @@ -442,6 +478,18 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEnd(const expression::ObjectExpression& node , bool callVirtualBase = true); + /** + * \brief Visitor which is called at the beginning of the expression::PrivateIdentifier node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::PrivateIdentifier& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::PrivateIdentifier node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::PrivateIdentifier& node , bool callVirtualBase = true); + /** * \brief Visitor which is called at the beginning of the expression::Property node visiting. * \param node [in] The node which is visited. @@ -970,6 +1018,18 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEnd(const structure::MethodDefinition& node , bool callVirtualBase = true); + /** + * \brief Visitor which is called at the beginning of the structure::PropertyDefinition node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const structure::PropertyDefinition& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the structure::PropertyDefinition node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const structure::PropertyDefinition& node , bool callVirtualBase = true); + /** * \brief Edge visitor for comments edge which. * \param begin [in] The reference of the node the edge starts from. @@ -1026,6 +1086,20 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEndExportAllDeclaration_HasSource(const declaration::ExportAllDeclaration& begin, const expression::Literal& end); + /** + * \brief Edge visitor for hasExported edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExportAllDeclaration_HasExported(const declaration::ExportAllDeclaration& begin, const expression::Identifier& end); + + /** + * \brief Edge end visitor for hasExported edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndExportAllDeclaration_HasExported(const declaration::ExportAllDeclaration& begin, const expression::Identifier& end); + /** * \brief Edge visitor for hasDeclaration edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. @@ -1213,14 +1287,14 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const expression::Expression& end); + virtual void visitBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const base::Positioned& end); /** * \brief Edge end visitor for hasLeft edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitEndBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const expression::Expression& end); + virtual void visitEndBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const base::Positioned& end); /** * \brief Edge visitor for hasRight edge which is called when the subtree of this edge is started. @@ -1278,6 +1352,20 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEndCallExpression_Calls(const expression::CallExpression& begin, const statement::Function& end); + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitChainExpression_HasExpression(const expression::ChainExpression& begin, const expression::ChainElement& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndChainExpression_HasExpression(const expression::ChainExpression& begin, const expression::ChainElement& end); + /** * \brief Edge visitor for hasAlternate edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. @@ -1334,6 +1422,20 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEndIdentifier_RefersTo(const expression::Identifier& begin, const base::Positioned& end); + /** + * \brief Edge visitor for hasSource edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitImportExpression_HasSource(const expression::ImportExpression& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasSource edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndImportExpression_HasSource(const expression::ImportExpression& begin, const expression::Expression& end); + /** * \brief Edge visitor for hasLeft edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. @@ -1367,14 +1469,14 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitMemberExpression_HasProperty(const expression::MemberExpression& begin, const expression::Expression& end); + virtual void visitMemberExpression_HasProperty(const expression::MemberExpression& begin, const base::Positioned& end); /** * \brief Edge end visitor for hasProperty edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitEndMemberExpression_HasProperty(const expression::MemberExpression& begin, const expression::Expression& end); + virtual void visitEndMemberExpression_HasProperty(const expression::MemberExpression& begin, const base::Positioned& end); /** * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. @@ -2221,14 +2323,14 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitClassBody_HasBody(const structure::ClassBody& begin, const structure::MethodDefinition& end); + virtual void visitClassBody_HasBody(const structure::ClassBody& begin, const base::Positioned& end); /** * \brief Edge end visitor for hasBody edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitEndClassBody_HasBody(const structure::ClassBody& begin, const structure::MethodDefinition& end); + virtual void visitEndClassBody_HasBody(const structure::ClassBody& begin, const base::Positioned& end); /** * \brief Edge visitor for hasExported edge which is called when the subtree of this edge is started. @@ -2263,14 +2365,14 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitMethodDefinition_HasKey(const structure::MethodDefinition& begin, const expression::Expression& end); + virtual void visitMethodDefinition_HasKey(const structure::MethodDefinition& begin, const base::Positioned& end); /** * \brief Edge end visitor for hasKey edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitEndMethodDefinition_HasKey(const structure::MethodDefinition& begin, const expression::Expression& end); + virtual void visitEndMethodDefinition_HasKey(const structure::MethodDefinition& begin, const base::Positioned& end); /** * \brief Edge visitor for hasValue edge which is called when the subtree of this edge is started. @@ -2300,6 +2402,34 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEndModuleSpecifier_HasLocal(const structure::ModuleSpecifier& begin, const expression::Identifier& end); + /** + * \brief Edge visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPropertyDefinition_HasKey(const structure::PropertyDefinition& begin, const base::Positioned& end); + + /** + * \brief Edge end visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndPropertyDefinition_HasKey(const structure::PropertyDefinition& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPropertyDefinition_HasValue(const structure::PropertyDefinition& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndPropertyDefinition_HasValue(const structure::PropertyDefinition& begin, const expression::Expression& end); + protected: /** \internal \brief Stores the depth position in the ASG. */ unsigned depth; diff --git a/lib/javascript/inc/visitors/VisitorAbstractNodes.h b/lib/javascript/inc/visitors/VisitorAbstractNodes.h index 8f56b69..a59d4a5 100644 --- a/lib/javascript/inc/visitors/VisitorAbstractNodes.h +++ b/lib/javascript/inc/visitors/VisitorAbstractNodes.h @@ -306,32 +306,32 @@ namespace columbus { namespace javascript { namespace asg { virtual void visitEnd(const expression::AssignmentExpression& node , bool callVirtualBase = true); /** - * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Property,..) of the expression::AssignmentProperty node. + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Expression,..) of the expression::AwaitExpression node. * \param node [in] The node which is visited. * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). */ - virtual void visit(const expression::AssignmentProperty& node , bool callVirtualBase = true); + virtual void visit(const expression::AwaitExpression& node , bool callVirtualBase = true); /** - * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Property,..) of the expression::AssignmentProperty node. + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Expression,..) of the expression::AwaitExpression node. * \param node [in] The node which is visited. * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). */ - virtual void visitEnd(const expression::AssignmentProperty& node , bool callVirtualBase = true); + virtual void visitEnd(const expression::AwaitExpression& node , bool callVirtualBase = true); /** - * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Expression,..) of the expression::AwaitExpression node. + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Literal,..) of the expression::BigIntLiteral node. * \param node [in] The node which is visited. * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). */ - virtual void visit(const expression::AwaitExpression& node , bool callVirtualBase = true); + virtual void visit(const expression::BigIntLiteral& node , bool callVirtualBase = true); /** - * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Expression,..) of the expression::AwaitExpression node. + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Literal,..) of the expression::BigIntLiteral node. * \param node [in] The node which is visited. * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). */ - virtual void visitEnd(const expression::AwaitExpression& node , bool callVirtualBase = true); + virtual void visitEnd(const expression::BigIntLiteral& node , bool callVirtualBase = true); /** * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Expression,..) of the expression::BinaryExpression node. @@ -375,6 +375,34 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEnd(const expression::CallExpression& node , bool callVirtualBase = true); + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Positioned,..) of the expression::ChainElement node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::ChainElement& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (base::Positioned,..) of the expression::ChainElement node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::ChainElement& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Expression,..) of the expression::ChainExpression node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::ChainExpression& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Expression,..) of the expression::ChainExpression node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::ChainExpression& node , bool callVirtualBase = true); + /** * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Expression,..) of the expression::ClassExpression node. * \param node [in] The node which is visited. @@ -445,6 +473,20 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEnd(const expression::Identifier& node , bool callVirtualBase = true); + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Expression,..) of the expression::ImportExpression node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::ImportExpression& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Expression,..) of the expression::ImportExpression node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::ImportExpression& node , bool callVirtualBase = true); + /** * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Positioned,..) of the expression::Literal node. * \param node [in] The node which is visited. @@ -557,6 +599,20 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEnd(const expression::ObjectExpression& node , bool callVirtualBase = true); + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Positioned,..) of the expression::PrivateIdentifier node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::PrivateIdentifier& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (base::Positioned,..) of the expression::PrivateIdentifier node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::PrivateIdentifier& node , bool callVirtualBase = true); + /** * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Positioned,..) of the expression::Property node. * \param node [in] The node which is visited. @@ -1243,6 +1299,20 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEnd(const structure::ModuleSpecifier& node , bool callVirtualBase = true); + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Positioned,..) of the structure::PropertyDefinition node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const structure::PropertyDefinition& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (base::Positioned,..) of the structure::PropertyDefinition node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const structure::PropertyDefinition& node , bool callVirtualBase = true); + }; // VisitorAbstractNodes diff --git a/lib/javascript/inc/visitors/VisitorAsgStat.h b/lib/javascript/inc/visitors/VisitorAsgStat.h index 5c8bbec..4de5333 100644 --- a/lib/javascript/inc/visitors/VisitorAsgStat.h +++ b/lib/javascript/inc/visitors/VisitorAsgStat.h @@ -162,16 +162,16 @@ namespace columbus { namespace javascript { namespace asg { virtual void visit(const expression::AssignmentExpression& node,bool callVirtualBase = true); /** - * \brief Visitor to create statistics about expression::AssignmentProperty node. + * \brief Visitor to create statistics about expression::AwaitExpression node. * \param node [in] The node which is visited. */ - virtual void visit(const expression::AssignmentProperty& node,bool callVirtualBase = true); + virtual void visit(const expression::AwaitExpression& node,bool callVirtualBase = true); /** - * \brief Visitor to create statistics about expression::AwaitExpression node. + * \brief Visitor to create statistics about expression::BigIntLiteral node. * \param node [in] The node which is visited. */ - virtual void visit(const expression::AwaitExpression& node,bool callVirtualBase = true); + virtual void visit(const expression::BigIntLiteral& node,bool callVirtualBase = true); /** * \brief Visitor to create statistics about expression::BinaryExpression node. @@ -191,6 +191,18 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visit(const expression::CallExpression& node,bool callVirtualBase = true); + /** + * \brief Visitor to create statistics about expression::ChainElement node. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::ChainElement& node,bool callVirtualBase = true); + + /** + * \brief Visitor to create statistics about expression::ChainExpression node. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::ChainExpression& node,bool callVirtualBase = true); + /** * \brief Visitor to create statistics about expression::ClassExpression node. * \param node [in] The node which is visited. @@ -221,6 +233,12 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visit(const expression::Identifier& node,bool callVirtualBase = true); + /** + * \brief Visitor to create statistics about expression::ImportExpression node. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::ImportExpression& node,bool callVirtualBase = true); + /** * \brief Visitor to create statistics about expression::Literal node. * \param node [in] The node which is visited. @@ -269,6 +287,12 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visit(const expression::ObjectExpression& node,bool callVirtualBase = true); + /** + * \brief Visitor to create statistics about expression::PrivateIdentifier node. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::PrivateIdentifier& node,bool callVirtualBase = true); + /** * \brief Visitor to create statistics about expression::Property node. * \param node [in] The node which is visited. @@ -563,6 +587,12 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visit(const structure::ModuleSpecifier& node,bool callVirtualBase = true); + /** + * \brief Visitor to create statistics about structure::PropertyDefinition node. + * \param node [in] The node which is visited. + */ + virtual void visit(const structure::PropertyDefinition& node,bool callVirtualBase = true); + /** * \brief Edge visitor for comments edge which. * \param begin [in] The reference of the node the edge starts from. @@ -591,6 +621,13 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitExportAllDeclaration_HasSource(const declaration::ExportAllDeclaration& begin, const expression::Literal& end); + /** + * \brief Edge visitor for hasExported edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExportAllDeclaration_HasExported(const declaration::ExportAllDeclaration& begin, const expression::Identifier& end); + /** * \brief Edge visitor for hasDeclaration edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. @@ -687,7 +724,7 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const expression::Expression& end); + virtual void visitBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const base::Positioned& end); /** * \brief Edge visitor for hasRight edge which is called when the subtree of this edge is started. @@ -717,6 +754,13 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitCallExpression_Calls(const expression::CallExpression& begin, const statement::Function& end); + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitChainExpression_HasExpression(const expression::ChainExpression& begin, const expression::ChainElement& end); + /** * \brief Edge visitor for hasAlternate edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. @@ -745,6 +789,13 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitIdentifier_RefersTo(const expression::Identifier& begin, const base::Positioned& end); + /** + * \brief Edge visitor for hasSource edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitImportExpression_HasSource(const expression::ImportExpression& begin, const expression::Expression& end); + /** * \brief Edge visitor for hasLeft edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. @@ -764,7 +815,7 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitMemberExpression_HasProperty(const expression::MemberExpression& begin, const expression::Expression& end); + virtual void visitMemberExpression_HasProperty(const expression::MemberExpression& begin, const base::Positioned& end); /** * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. @@ -1191,7 +1242,7 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitClassBody_HasBody(const structure::ClassBody& begin, const structure::MethodDefinition& end); + virtual void visitClassBody_HasBody(const structure::ClassBody& begin, const base::Positioned& end); /** * \brief Edge visitor for hasExported edge which is called when the subtree of this edge is started. @@ -1212,7 +1263,7 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitMethodDefinition_HasKey(const structure::MethodDefinition& begin, const expression::Expression& end); + virtual void visitMethodDefinition_HasKey(const structure::MethodDefinition& begin, const base::Positioned& end); /** * \brief Edge visitor for hasValue edge which is called when the subtree of this edge is started. @@ -1228,15 +1279,29 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitModuleSpecifier_HasLocal(const structure::ModuleSpecifier& begin, const expression::Identifier& end); + /** + * \brief Edge visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPropertyDefinition_HasKey(const structure::PropertyDefinition& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPropertyDefinition_HasValue(const structure::PropertyDefinition& begin, const expression::Expression& end); + protected: /** \internal \brief Contains statistics about nodes. */ - unsigned int nodeStatSimple[86]; + unsigned int nodeStatSimple[91]; /** \internal \brief Contains statistics about nodes (where the node is counted in all parents statistic). */ - unsigned int nodeStatParent[86]; + unsigned int nodeStatParent[91]; /** \internal \brief Contains statistics about edges. */ - unsigned int edgeStat[95]; + unsigned int edgeStat[100]; friend class Factory; diff --git a/lib/javascript/inc/visitors/VisitorFilter.h b/lib/javascript/inc/visitors/VisitorFilter.h index 0a1bcbf..71a2dbe 100644 --- a/lib/javascript/inc/visitors/VisitorFilter.h +++ b/lib/javascript/inc/visitors/VisitorFilter.h @@ -143,13 +143,13 @@ namespace columbus { namespace javascript { namespace asg { * \brief Deselects the actual node (and only this). * \param node [in] The node which is visited. */ - virtual void visitEnd(const expression::AssignmentProperty& node , bool callVirtualBase = true); + virtual void visitEnd(const expression::AwaitExpression& node , bool callVirtualBase = true); /** * \brief Deselects the actual node (and only this). * \param node [in] The node which is visited. */ - virtual void visitEnd(const expression::AwaitExpression& node , bool callVirtualBase = true); + virtual void visitEnd(const expression::BigIntLiteral& node , bool callVirtualBase = true); /** * \brief Deselects the actual node (and only this). @@ -169,6 +169,18 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEnd(const expression::CallExpression& node , bool callVirtualBase = true); + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ChainElement& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ChainExpression& node , bool callVirtualBase = true); + /** * \brief Deselects the actual node (and only this). * \param node [in] The node which is visited. @@ -193,6 +205,12 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEnd(const expression::Identifier& node , bool callVirtualBase = true); + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ImportExpression& node , bool callVirtualBase = true); + /** * \brief Deselects the actual node (and only this). * \param node [in] The node which is visited. @@ -235,6 +253,12 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEnd(const expression::ObjectExpression& node , bool callVirtualBase = true); + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::PrivateIdentifier& node , bool callVirtualBase = true); + /** * \brief Deselects the actual node (and only this). * \param node [in] The node which is visited. @@ -499,6 +523,12 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEnd(const structure::MethodDefinition& node , bool callVirtualBase = true); + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const structure::PropertyDefinition& node , bool callVirtualBase = true); + }; // VisitorFilter diff --git a/lib/javascript/inc/visitors/VisitorGraphml.h b/lib/javascript/inc/visitors/VisitorGraphml.h index 24a73fd..ad41442 100644 --- a/lib/javascript/inc/visitors/VisitorGraphml.h +++ b/lib/javascript/inc/visitors/VisitorGraphml.h @@ -76,16 +76,19 @@ namespace columbus { namespace javascript { namespace asg { cmpTable.insert( std::make_pair( "ArrayExpression", &Common::getIsArrayExpression)); cmpTable.insert( std::make_pair( "ArrowFunctionExpression", &Common::getIsArrowFunctionExpression)); cmpTable.insert( std::make_pair( "AssignmentExpression", &Common::getIsAssignmentExpression)); - cmpTable.insert( std::make_pair( "AssignmentProperty", &Common::getIsAssignmentProperty)); cmpTable.insert( std::make_pair( "AwaitExpression", &Common::getIsAwaitExpression)); + cmpTable.insert( std::make_pair( "BigIntLiteral", &Common::getIsBigIntLiteral)); cmpTable.insert( std::make_pair( "BinaryExpression", &Common::getIsBinaryExpression)); cmpTable.insert( std::make_pair( "BooleanLiteral", &Common::getIsBooleanLiteral)); cmpTable.insert( std::make_pair( "CallExpression", &Common::getIsCallExpression)); + cmpTable.insert( std::make_pair( "ChainElement", &Common::getIsChainElement)); + cmpTable.insert( std::make_pair( "ChainExpression", &Common::getIsChainExpression)); cmpTable.insert( std::make_pair( "ClassExpression", &Common::getIsClassExpression)); cmpTable.insert( std::make_pair( "ConditionalExpression", &Common::getIsConditionalExpression)); cmpTable.insert( std::make_pair( "Expression", &Common::getIsExpression)); cmpTable.insert( std::make_pair( "FunctionExpression", &Common::getIsFunctionExpression)); cmpTable.insert( std::make_pair( "Identifier", &Common::getIsIdentifier)); + cmpTable.insert( std::make_pair( "ImportExpression", &Common::getIsImportExpression)); cmpTable.insert( std::make_pair( "Literal", &Common::getIsLiteral)); cmpTable.insert( std::make_pair( "LogicalExpression", &Common::getIsLogicalExpression)); cmpTable.insert( std::make_pair( "MemberExpression", &Common::getIsMemberExpression)); @@ -94,6 +97,7 @@ namespace columbus { namespace javascript { namespace asg { cmpTable.insert( std::make_pair( "NullLiteral", &Common::getIsNullLiteral)); cmpTable.insert( std::make_pair( "NumberLiteral", &Common::getIsNumberLiteral)); cmpTable.insert( std::make_pair( "ObjectExpression", &Common::getIsObjectExpression)); + cmpTable.insert( std::make_pair( "PrivateIdentifier", &Common::getIsPrivateIdentifier)); cmpTable.insert( std::make_pair( "Property", &Common::getIsProperty)); cmpTable.insert( std::make_pair( "RegExpLiteral", &Common::getIsRegExpLiteral)); cmpTable.insert( std::make_pair( "SequenceExpression", &Common::getIsSequenceExpression)); @@ -143,6 +147,7 @@ namespace columbus { namespace javascript { namespace asg { cmpTable.insert( std::make_pair( "ImportSpecifier", &Common::getIsImportSpecifier)); cmpTable.insert( std::make_pair( "MethodDefinition", &Common::getIsMethodDefinition)); cmpTable.insert( std::make_pair( "ModuleSpecifier", &Common::getIsModuleSpecifier)); + cmpTable.insert( std::make_pair( "PropertyDefinition", &Common::getIsPropertyDefinition)); return cmpTable; } @@ -170,16 +175,19 @@ namespace columbus { namespace javascript { namespace asg { types.insert( "expression::ArrayExpression"); types.insert( "expression::ArrowFunctionExpression"); types.insert( "expression::AssignmentExpression"); - types.insert( "expression::AssignmentProperty"); types.insert( "expression::AwaitExpression"); + types.insert( "expression::BigIntLiteral"); types.insert( "expression::BinaryExpression"); types.insert( "expression::BooleanLiteral"); types.insert( "expression::CallExpression"); + types.insert( "expression::ChainElement"); + types.insert( "expression::ChainExpression"); types.insert( "expression::ClassExpression"); types.insert( "expression::ConditionalExpression"); types.insert( "expression::Expression"); types.insert( "expression::FunctionExpression"); types.insert( "expression::Identifier"); + types.insert( "expression::ImportExpression"); types.insert( "expression::Literal"); types.insert( "expression::LogicalExpression"); types.insert( "expression::MemberExpression"); @@ -188,6 +196,7 @@ namespace columbus { namespace javascript { namespace asg { types.insert( "expression::NullLiteral"); types.insert( "expression::NumberLiteral"); types.insert( "expression::ObjectExpression"); + types.insert( "expression::PrivateIdentifier"); types.insert( "expression::Property"); types.insert( "expression::RegExpLiteral"); types.insert( "expression::SequenceExpression"); @@ -237,6 +246,7 @@ namespace columbus { namespace javascript { namespace asg { types.insert( "structure::ImportSpecifier"); types.insert( "structure::MethodDefinition"); types.insert( "structure::ModuleSpecifier"); + types.insert( "structure::PropertyDefinition"); return types; } @@ -459,28 +469,28 @@ namespace columbus { namespace javascript { namespace asg { virtual void visitEnd(const expression::AssignmentExpression& node, bool callVirtualBase = true); /** - * \brief Writes the Graphml representation of the expression::AssignmentProperty node into the output file. + * \brief Writes the Graphml representation of the expression::AwaitExpression node into the output file. * \param node [in] The node which is visited. */ - virtual void visit(const expression::AssignmentProperty& node, bool callVirtualBase = true); + virtual void visit(const expression::AwaitExpression& node, bool callVirtualBase = true); /** - * \brief Converts the expression::AssignmentProperty node. + * \brief Converts the expression::AwaitExpression node. * \param node [in] The node which is visited. */ - virtual void visitEnd(const expression::AssignmentProperty& node, bool callVirtualBase = true); + virtual void visitEnd(const expression::AwaitExpression& node, bool callVirtualBase = true); /** - * \brief Writes the Graphml representation of the expression::AwaitExpression node into the output file. + * \brief Writes the Graphml representation of the expression::BigIntLiteral node into the output file. * \param node [in] The node which is visited. */ - virtual void visit(const expression::AwaitExpression& node, bool callVirtualBase = true); + virtual void visit(const expression::BigIntLiteral& node, bool callVirtualBase = true); /** - * \brief Converts the expression::AwaitExpression node. + * \brief Converts the expression::BigIntLiteral node. * \param node [in] The node which is visited. */ - virtual void visitEnd(const expression::AwaitExpression& node, bool callVirtualBase = true); + virtual void visitEnd(const expression::BigIntLiteral& node, bool callVirtualBase = true); /** * \brief Writes the Graphml representation of the expression::BinaryExpression node into the output file. @@ -518,6 +528,30 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEnd(const expression::CallExpression& node, bool callVirtualBase = true); + /** + * \brief Writes the Graphml representation of the expression::ChainElement node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::ChainElement& node, bool callVirtualBase = true); + + /** + * \brief Converts the expression::ChainElement node. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ChainElement& node, bool callVirtualBase = true); + + /** + * \brief Writes the Graphml representation of the expression::ChainExpression node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::ChainExpression& node, bool callVirtualBase = true); + + /** + * \brief Converts the expression::ChainExpression node. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ChainExpression& node, bool callVirtualBase = true); + /** * \brief Writes the Graphml representation of the expression::ClassExpression node into the output file. * \param node [in] The node which is visited. @@ -566,6 +600,18 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEnd(const expression::Identifier& node, bool callVirtualBase = true); + /** + * \brief Writes the Graphml representation of the expression::ImportExpression node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::ImportExpression& node, bool callVirtualBase = true); + + /** + * \brief Converts the expression::ImportExpression node. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ImportExpression& node, bool callVirtualBase = true); + /** * \brief Writes the Graphml representation of the expression::LogicalExpression node into the output file. * \param node [in] The node which is visited. @@ -650,6 +696,18 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEnd(const expression::ObjectExpression& node, bool callVirtualBase = true); + /** + * \brief Writes the Graphml representation of the expression::PrivateIdentifier node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::PrivateIdentifier& node, bool callVirtualBase = true); + + /** + * \brief Converts the expression::PrivateIdentifier node. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::PrivateIdentifier& node, bool callVirtualBase = true); + /** * \brief Writes the Graphml representation of the expression::Property node into the output file. * \param node [in] The node which is visited. @@ -1178,6 +1236,18 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEnd(const structure::MethodDefinition& node, bool callVirtualBase = true); + /** + * \brief Writes the Graphml representation of the structure::PropertyDefinition node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const structure::PropertyDefinition& node, bool callVirtualBase = true); + + /** + * \brief Converts the structure::PropertyDefinition node. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const structure::PropertyDefinition& node, bool callVirtualBase = true); + /** * \brief Edge visitor for comments edge which. * \param begin [in] The reference of the node the edge starts from. @@ -1206,6 +1276,13 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitExportAllDeclaration_HasSource(const declaration::ExportAllDeclaration& begin, const expression::Literal& end); + /** + * \brief Edge visitor for hasExported edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExportAllDeclaration_HasExported(const declaration::ExportAllDeclaration& begin, const expression::Identifier& end); + /** * \brief Edge visitor for hasDeclaration edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. @@ -1302,7 +1379,7 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const expression::Expression& end); + virtual void visitBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const base::Positioned& end); /** * \brief Edge visitor for hasRight edge which is called when the subtree of this edge is started. @@ -1332,6 +1409,13 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitCallExpression_Calls(const expression::CallExpression& begin, const statement::Function& end); + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitChainExpression_HasExpression(const expression::ChainExpression& begin, const expression::ChainElement& end); + /** * \brief Edge visitor for hasAlternate edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. @@ -1360,6 +1444,13 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitIdentifier_RefersTo(const expression::Identifier& begin, const base::Positioned& end); + /** + * \brief Edge visitor for hasSource edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitImportExpression_HasSource(const expression::ImportExpression& begin, const expression::Expression& end); + /** * \brief Edge visitor for hasLeft edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. @@ -1379,7 +1470,7 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitMemberExpression_HasProperty(const expression::MemberExpression& begin, const expression::Expression& end); + virtual void visitMemberExpression_HasProperty(const expression::MemberExpression& begin, const base::Positioned& end); /** * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. @@ -1806,7 +1897,7 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitClassBody_HasBody(const structure::ClassBody& begin, const structure::MethodDefinition& end); + virtual void visitClassBody_HasBody(const structure::ClassBody& begin, const base::Positioned& end); /** * \brief Edge visitor for hasExported edge which is called when the subtree of this edge is started. @@ -1827,7 +1918,7 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitMethodDefinition_HasKey(const structure::MethodDefinition& begin, const expression::Expression& end); + virtual void visitMethodDefinition_HasKey(const structure::MethodDefinition& begin, const base::Positioned& end); /** * \brief Edge visitor for hasValue edge which is called when the subtree of this edge is started. @@ -1843,6 +1934,20 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitModuleSpecifier_HasLocal(const structure::ModuleSpecifier& begin, const expression::Identifier& end); + /** + * \brief Edge visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPropertyDefinition_HasKey(const structure::PropertyDefinition& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPropertyDefinition_HasValue(const structure::PropertyDefinition& begin, const expression::Expression& end); + protected: /** @@ -1961,15 +2066,15 @@ namespace columbus { namespace javascript { namespace asg { /** * \internal - * \brief Converts the attributes of the expression::AssignmentProperty node. + * \brief Converts the attributes of the expression::AwaitExpression node. */ - void addAttributeToContent(const expression::AssignmentProperty& node, std::string& content, bool callVirtualBase); + void addAttributeToContent(const expression::AwaitExpression& node, std::string& content, bool callVirtualBase); /** * \internal - * \brief Converts the attributes of the expression::AwaitExpression node. + * \brief Converts the attributes of the expression::BigIntLiteral node. */ - void addAttributeToContent(const expression::AwaitExpression& node, std::string& content, bool callVirtualBase); + void addAttributeToContent(const expression::BigIntLiteral& node, std::string& content, bool callVirtualBase); /** * \internal @@ -1989,6 +2094,18 @@ namespace columbus { namespace javascript { namespace asg { */ void addAttributeToContent(const expression::CallExpression& node, std::string& content, bool callVirtualBase); + /** + * \internal + * \brief Converts the attributes of the expression::ChainElement node. + */ + void addAttributeToContent(const expression::ChainElement& node, std::string& content, bool callVirtualBase); + + /** + * \internal + * \brief Converts the attributes of the expression::ChainExpression node. + */ + void addAttributeToContent(const expression::ChainExpression& node, std::string& content, bool callVirtualBase); + /** * \internal * \brief Converts the attributes of the expression::ClassExpression node. @@ -2019,6 +2136,12 @@ namespace columbus { namespace javascript { namespace asg { */ void addAttributeToContent(const expression::Identifier& node, std::string& content, bool callVirtualBase); + /** + * \internal + * \brief Converts the attributes of the expression::ImportExpression node. + */ + void addAttributeToContent(const expression::ImportExpression& node, std::string& content, bool callVirtualBase); + /** * \internal * \brief Converts the attributes of the expression::Literal node. @@ -2067,6 +2190,12 @@ namespace columbus { namespace javascript { namespace asg { */ void addAttributeToContent(const expression::ObjectExpression& node, std::string& content, bool callVirtualBase); + /** + * \internal + * \brief Converts the attributes of the expression::PrivateIdentifier node. + */ + void addAttributeToContent(const expression::PrivateIdentifier& node, std::string& content, bool callVirtualBase); + /** * \internal * \brief Converts the attributes of the expression::Property node. @@ -2361,6 +2490,12 @@ namespace columbus { namespace javascript { namespace asg { */ void addAttributeToContent(const structure::ModuleSpecifier& node, std::string& content, bool callVirtualBase); + /** + * \internal + * \brief Converts the attributes of the structure::PropertyDefinition node. + */ + void addAttributeToContent(const structure::PropertyDefinition& node, std::string& content, bool callVirtualBase); + /** \internal \brief The ofstream into the DOT graph will be written. */ columbus::io::GraphmlIO &io; diff --git a/lib/javascript/inc/visitors/VisitorJAVASCRIPTML.h b/lib/javascript/inc/visitors/VisitorJAVASCRIPTML.h index 8a3b186..418596c 100644 --- a/lib/javascript/inc/visitors/VisitorJAVASCRIPTML.h +++ b/lib/javascript/inc/visitors/VisitorJAVASCRIPTML.h @@ -244,28 +244,28 @@ namespace columbus { namespace javascript { namespace asg { virtual void visitEnd(const expression::AssignmentExpression& node, bool callVirtualBase = true); /** - * \brief Writes the XML representation of the expression::AssignmentProperty node into the output file. + * \brief Writes the XML representation of the expression::AwaitExpression node into the output file. * \param node [in] The node which is visited. */ - virtual void visit(const expression::AssignmentProperty& node, bool callVirtualBase = true); + virtual void visit(const expression::AwaitExpression& node, bool callVirtualBase = true); /** - * \brief Writes the end part of XML representation of the expression::AssignmentProperty node into the output file. + * \brief Writes the end part of XML representation of the expression::AwaitExpression node into the output file. * \param node [in] The node which is visited. */ - virtual void visitEnd(const expression::AssignmentProperty& node, bool callVirtualBase = true); + virtual void visitEnd(const expression::AwaitExpression& node, bool callVirtualBase = true); /** - * \brief Writes the XML representation of the expression::AwaitExpression node into the output file. + * \brief Writes the XML representation of the expression::BigIntLiteral node into the output file. * \param node [in] The node which is visited. */ - virtual void visit(const expression::AwaitExpression& node, bool callVirtualBase = true); + virtual void visit(const expression::BigIntLiteral& node, bool callVirtualBase = true); /** - * \brief Writes the end part of XML representation of the expression::AwaitExpression node into the output file. + * \brief Writes the end part of XML representation of the expression::BigIntLiteral node into the output file. * \param node [in] The node which is visited. */ - virtual void visitEnd(const expression::AwaitExpression& node, bool callVirtualBase = true); + virtual void visitEnd(const expression::BigIntLiteral& node, bool callVirtualBase = true); /** * \brief Writes the XML representation of the expression::BinaryExpression node into the output file. @@ -303,6 +303,30 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEnd(const expression::CallExpression& node, bool callVirtualBase = true); + /** + * \brief Writes the XML representation of the expression::ChainElement node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::ChainElement& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::ChainElement node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ChainElement& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::ChainExpression node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::ChainExpression& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::ChainExpression node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ChainExpression& node, bool callVirtualBase = true); + /** * \brief Writes the XML representation of the expression::ClassExpression node into the output file. * \param node [in] The node which is visited. @@ -351,6 +375,18 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEnd(const expression::Identifier& node, bool callVirtualBase = true); + /** + * \brief Writes the XML representation of the expression::ImportExpression node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::ImportExpression& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::ImportExpression node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ImportExpression& node, bool callVirtualBase = true); + /** * \brief Writes the XML representation of the expression::LogicalExpression node into the output file. * \param node [in] The node which is visited. @@ -435,6 +471,18 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEnd(const expression::ObjectExpression& node, bool callVirtualBase = true); + /** + * \brief Writes the XML representation of the expression::PrivateIdentifier node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::PrivateIdentifier& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::PrivateIdentifier node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::PrivateIdentifier& node, bool callVirtualBase = true); + /** * \brief Writes the XML representation of the expression::Property node into the output file. * \param node [in] The node which is visited. @@ -963,6 +1011,18 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEnd(const structure::MethodDefinition& node, bool callVirtualBase = true); + /** + * \brief Writes the XML representation of the structure::PropertyDefinition node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const structure::PropertyDefinition& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the structure::PropertyDefinition node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const structure::PropertyDefinition& node, bool callVirtualBase = true); + /** * \brief Edge visitor for comments edge which. * \param begin [in] The reference of the node the edge starts from. @@ -1019,6 +1079,20 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEndExportAllDeclaration_HasSource(const declaration::ExportAllDeclaration& begin, const expression::Literal& end); + /** + * \brief Edge visitor for hasExported edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExportAllDeclaration_HasExported(const declaration::ExportAllDeclaration& begin, const expression::Identifier& end); + + /** + * \brief Edge end visitor for hasExported edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndExportAllDeclaration_HasExported(const declaration::ExportAllDeclaration& begin, const expression::Identifier& end); + /** * \brief Edge visitor for hasDeclaration edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. @@ -1206,14 +1280,14 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const expression::Expression& end); + virtual void visitBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const base::Positioned& end); /** * \brief Edge end visitor for hasLeft edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitEndBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const expression::Expression& end); + virtual void visitEndBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const base::Positioned& end); /** * \brief Edge visitor for hasRight edge which is called when the subtree of this edge is started. @@ -1271,6 +1345,20 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEndCallExpression_Calls(const expression::CallExpression& begin, const statement::Function& end); + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitChainExpression_HasExpression(const expression::ChainExpression& begin, const expression::ChainElement& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndChainExpression_HasExpression(const expression::ChainExpression& begin, const expression::ChainElement& end); + /** * \brief Edge visitor for hasAlternate edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. @@ -1327,6 +1415,20 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEndIdentifier_RefersTo(const expression::Identifier& begin, const base::Positioned& end); + /** + * \brief Edge visitor for hasSource edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitImportExpression_HasSource(const expression::ImportExpression& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasSource edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndImportExpression_HasSource(const expression::ImportExpression& begin, const expression::Expression& end); + /** * \brief Edge visitor for hasLeft edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. @@ -1360,14 +1462,14 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitMemberExpression_HasProperty(const expression::MemberExpression& begin, const expression::Expression& end); + virtual void visitMemberExpression_HasProperty(const expression::MemberExpression& begin, const base::Positioned& end); /** * \brief Edge end visitor for hasProperty edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitEndMemberExpression_HasProperty(const expression::MemberExpression& begin, const expression::Expression& end); + virtual void visitEndMemberExpression_HasProperty(const expression::MemberExpression& begin, const base::Positioned& end); /** * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. @@ -2214,14 +2316,14 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitClassBody_HasBody(const structure::ClassBody& begin, const structure::MethodDefinition& end); + virtual void visitClassBody_HasBody(const structure::ClassBody& begin, const base::Positioned& end); /** * \brief Edge end visitor for hasBody edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitEndClassBody_HasBody(const structure::ClassBody& begin, const structure::MethodDefinition& end); + virtual void visitEndClassBody_HasBody(const structure::ClassBody& begin, const base::Positioned& end); /** * \brief Edge visitor for hasExported edge which is called when the subtree of this edge is started. @@ -2256,14 +2358,14 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitMethodDefinition_HasKey(const structure::MethodDefinition& begin, const expression::Expression& end); + virtual void visitMethodDefinition_HasKey(const structure::MethodDefinition& begin, const base::Positioned& end); /** * \brief Edge end visitor for hasKey edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitEndMethodDefinition_HasKey(const structure::MethodDefinition& begin, const expression::Expression& end); + virtual void visitEndMethodDefinition_HasKey(const structure::MethodDefinition& begin, const base::Positioned& end); /** * \brief Edge visitor for hasValue edge which is called when the subtree of this edge is started. @@ -2293,6 +2395,34 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEndModuleSpecifier_HasLocal(const structure::ModuleSpecifier& begin, const expression::Identifier& end); + /** + * \brief Edge visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPropertyDefinition_HasKey(const structure::PropertyDefinition& begin, const base::Positioned& end); + + /** + * \brief Edge end visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndPropertyDefinition_HasKey(const structure::PropertyDefinition& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPropertyDefinition_HasValue(const structure::PropertyDefinition& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndPropertyDefinition_HasValue(const structure::PropertyDefinition& begin, const expression::Expression& end); + protected: /** @@ -2429,15 +2559,15 @@ namespace columbus { namespace javascript { namespace asg { /** * \internal - * \brief Writes out the attributes of the expression::AssignmentProperty node. + * \brief Writes out the attributes of the expression::AwaitExpression node. */ - virtual void writeAttributes(const expression::AssignmentProperty& node, bool composite, bool bWithParent = true); + virtual void writeAttributes(const expression::AwaitExpression& node, bool composite, bool bWithParent = true); /** * \internal - * \brief Writes out the attributes of the expression::AwaitExpression node. + * \brief Writes out the attributes of the expression::BigIntLiteral node. */ - virtual void writeAttributes(const expression::AwaitExpression& node, bool composite, bool bWithParent = true); + virtual void writeAttributes(const expression::BigIntLiteral& node, bool composite, bool bWithParent = true); /** * \internal @@ -2457,6 +2587,18 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void writeAttributes(const expression::CallExpression& node, bool composite, bool bWithParent = true); + /** + * \internal + * \brief Writes out the attributes of the expression::ChainElement node. + */ + virtual void writeAttributes(const expression::ChainElement& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::ChainExpression node. + */ + virtual void writeAttributes(const expression::ChainExpression& node, bool composite, bool bWithParent = true); + /** * \internal * \brief Writes out the attributes of the expression::ClassExpression node. @@ -2487,6 +2629,12 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void writeAttributes(const expression::Identifier& node, bool composite, bool bWithParent = true); + /** + * \internal + * \brief Writes out the attributes of the expression::ImportExpression node. + */ + virtual void writeAttributes(const expression::ImportExpression& node, bool composite, bool bWithParent = true); + /** * \internal * \brief Writes out the attributes of the expression::Literal node. @@ -2535,6 +2683,12 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void writeAttributes(const expression::ObjectExpression& node, bool composite, bool bWithParent = true); + /** + * \internal + * \brief Writes out the attributes of the expression::PrivateIdentifier node. + */ + virtual void writeAttributes(const expression::PrivateIdentifier& node, bool composite, bool bWithParent = true); + /** * \internal * \brief Writes out the attributes of the expression::Property node. @@ -2829,6 +2983,12 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void writeAttributes(const structure::ModuleSpecifier& node, bool composite, bool bWithParent = true); + /** + * \internal + * \brief Writes out the attributes of the structure::PropertyDefinition node. + */ + virtual void writeAttributes(const structure::PropertyDefinition& node, bool composite, bool bWithParent = true); + /** \internal \brief The ofstrem into the xml will be written. */ std::ofstream &ofs; diff --git a/lib/javascript/inc/visitors/VisitorReverseEdges.h b/lib/javascript/inc/visitors/VisitorReverseEdges.h index 1555901..05024b2 100644 --- a/lib/javascript/inc/visitors/VisitorReverseEdges.h +++ b/lib/javascript/inc/visitors/VisitorReverseEdges.h @@ -94,6 +94,13 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitExportAllDeclaration_HasSource(const declaration::ExportAllDeclaration& begin, const expression::Literal& end); + /** + * \brief Edge visitor for hasExported edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExportAllDeclaration_HasExported(const declaration::ExportAllDeclaration& begin, const expression::Identifier& end); + /** * \brief Edge visitor for hasDeclaration edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. @@ -190,7 +197,7 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const expression::Expression& end); + virtual void visitBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const base::Positioned& end); /** * \brief Edge visitor for hasRight edge which is called when the subtree of this edge is started. @@ -220,6 +227,13 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitCallExpression_Calls(const expression::CallExpression& begin, const statement::Function& end); + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitChainExpression_HasExpression(const expression::ChainExpression& begin, const expression::ChainElement& end); + /** * \brief Edge visitor for hasAlternate edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. @@ -248,6 +262,13 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitIdentifier_RefersTo(const expression::Identifier& begin, const base::Positioned& end); + /** + * \brief Edge visitor for hasSource edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitImportExpression_HasSource(const expression::ImportExpression& begin, const expression::Expression& end); + /** * \brief Edge visitor for hasLeft edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. @@ -267,7 +288,7 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitMemberExpression_HasProperty(const expression::MemberExpression& begin, const expression::Expression& end); + virtual void visitMemberExpression_HasProperty(const expression::MemberExpression& begin, const base::Positioned& end); /** * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. @@ -694,7 +715,7 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitClassBody_HasBody(const structure::ClassBody& begin, const structure::MethodDefinition& end); + virtual void visitClassBody_HasBody(const structure::ClassBody& begin, const base::Positioned& end); /** * \brief Edge visitor for hasExported edge which is called when the subtree of this edge is started. @@ -715,7 +736,7 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitMethodDefinition_HasKey(const structure::MethodDefinition& begin, const expression::Expression& end); + virtual void visitMethodDefinition_HasKey(const structure::MethodDefinition& begin, const base::Positioned& end); /** * \brief Edge visitor for hasValue edge which is called when the subtree of this edge is started. @@ -731,6 +752,20 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitModuleSpecifier_HasLocal(const structure::ModuleSpecifier& begin, const expression::Identifier& end); + /** + * \brief Edge visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPropertyDefinition_HasKey(const structure::PropertyDefinition& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPropertyDefinition_HasValue(const structure::PropertyDefinition& begin, const expression::Expression& end); + protected: /** \internal \brief Edges are inserted into this ReverseEdges class. */ diff --git a/lib/javascript/inc/visitors/VisitorSimpleEdge.h b/lib/javascript/inc/visitors/VisitorSimpleEdge.h index df4db0b..65c9fec 100644 --- a/lib/javascript/inc/visitors/VisitorSimpleEdge.h +++ b/lib/javascript/inc/visitors/VisitorSimpleEdge.h @@ -95,6 +95,20 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEndExportAllDeclaration_HasSource(const declaration::ExportAllDeclaration& begin, const expression::Literal& end); + /** + * \brief Edge visitor for hasExported edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExportAllDeclaration_HasExported(const declaration::ExportAllDeclaration& begin, const expression::Identifier& end); + + /** + * \brief Edge end visitor for hasExported edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndExportAllDeclaration_HasExported(const declaration::ExportAllDeclaration& begin, const expression::Identifier& end); + /** * \brief Edge visitor for hasDeclaration edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. @@ -282,14 +296,14 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const expression::Expression& end); + virtual void visitBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const base::Positioned& end); /** * \brief Edge end visitor for hasLeft edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitEndBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const expression::Expression& end); + virtual void visitEndBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const base::Positioned& end); /** * \brief Edge visitor for hasRight edge which is called when the subtree of this edge is started. @@ -347,6 +361,20 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEndCallExpression_Calls(const expression::CallExpression& begin, const statement::Function& end); + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitChainExpression_HasExpression(const expression::ChainExpression& begin, const expression::ChainElement& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndChainExpression_HasExpression(const expression::ChainExpression& begin, const expression::ChainElement& end); + /** * \brief Edge visitor for hasAlternate edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. @@ -403,6 +431,20 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEndIdentifier_RefersTo(const expression::Identifier& begin, const base::Positioned& end); + /** + * \brief Edge visitor for hasSource edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitImportExpression_HasSource(const expression::ImportExpression& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasSource edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndImportExpression_HasSource(const expression::ImportExpression& begin, const expression::Expression& end); + /** * \brief Edge visitor for hasLeft edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. @@ -436,14 +478,14 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitMemberExpression_HasProperty(const expression::MemberExpression& begin, const expression::Expression& end); + virtual void visitMemberExpression_HasProperty(const expression::MemberExpression& begin, const base::Positioned& end); /** * \brief Edge end visitor for hasProperty edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitEndMemberExpression_HasProperty(const expression::MemberExpression& begin, const expression::Expression& end); + virtual void visitEndMemberExpression_HasProperty(const expression::MemberExpression& begin, const base::Positioned& end); /** * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. @@ -1290,14 +1332,14 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitClassBody_HasBody(const structure::ClassBody& begin, const structure::MethodDefinition& end); + virtual void visitClassBody_HasBody(const structure::ClassBody& begin, const base::Positioned& end); /** * \brief Edge end visitor for hasBody edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitEndClassBody_HasBody(const structure::ClassBody& begin, const structure::MethodDefinition& end); + virtual void visitEndClassBody_HasBody(const structure::ClassBody& begin, const base::Positioned& end); /** * \brief Edge visitor for hasExported edge which is called when the subtree of this edge is started. @@ -1332,14 +1374,14 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitMethodDefinition_HasKey(const structure::MethodDefinition& begin, const expression::Expression& end); + virtual void visitMethodDefinition_HasKey(const structure::MethodDefinition& begin, const base::Positioned& end); /** * \brief Edge end visitor for hasKey edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - virtual void visitEndMethodDefinition_HasKey(const structure::MethodDefinition& begin, const expression::Expression& end); + virtual void visitEndMethodDefinition_HasKey(const structure::MethodDefinition& begin, const base::Positioned& end); /** * \brief Edge visitor for hasValue edge which is called when the subtree of this edge is started. @@ -1369,6 +1411,34 @@ namespace columbus { namespace javascript { namespace asg { */ virtual void visitEndModuleSpecifier_HasLocal(const structure::ModuleSpecifier& begin, const expression::Identifier& end); + /** + * \brief Edge visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPropertyDefinition_HasKey(const structure::PropertyDefinition& begin, const base::Positioned& end); + + /** + * \brief Edge end visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndPropertyDefinition_HasKey(const structure::PropertyDefinition& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPropertyDefinition_HasValue(const structure::PropertyDefinition& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndPropertyDefinition_HasValue(const structure::PropertyDefinition& begin, const expression::Expression& end); + /** * \brief Edge visitor for all edge which is called when the subtree of this edge is finished. * \param begin [in] The reference of the node the edge starts from. diff --git a/lib/javascript/src/Common.cpp b/lib/javascript/src/Common.cpp index 73fe0a0..dcfca09 100644 --- a/lib/javascript/src/Common.cpp +++ b/lib/javascript/src/Common.cpp @@ -36,7 +36,8 @@ bool getIsNamed(const base::Base& node) { return ndk == ndkNamed || ndk == ndkProgram || - ndk == ndkIdentifier; + ndk == ndkIdentifier || + ndk == ndkPrivateIdentifier; } bool getIsPositioned(const base::Base& node) { @@ -46,26 +47,31 @@ bool getIsPositioned(const base::Base& node) { ndk == ndkComment || ndk == ndkProgram || ndk == ndkIdentifier || + ndk == ndkPrivateIdentifier || ndk == ndkModuleDeclaration || ndk == ndkExportNamedDeclaration || ndk == ndkImportDeclaration || ndk == ndkVariableDeclarator || + ndk == ndkChainElement || + ndk == ndkCallExpression || + ndk == ndkMemberExpression || ndk == ndkArrayExpression || ndk == ndkArrowFunctionExpression || ndk == ndkAssignmentExpression || ndk == ndkAwaitExpression || ndk == ndkBinaryExpression || - ndk == ndkCallExpression || + ndk == ndkChainExpression || ndk == ndkClassExpression || ndk == ndkConditionalExpression || ndk == ndkFunctionExpression || + ndk == ndkImportExpression || + ndk == ndkBigIntLiteral || ndk == ndkBooleanLiteral || ndk == ndkNullLiteral || ndk == ndkNumberLiteral || ndk == ndkRegExpLiteral || ndk == ndkStringLiteral || ndk == ndkLogicalExpression || - ndk == ndkMemberExpression || ndk == ndkMetaProperty || ndk == ndkNewExpression || ndk == ndkObjectExpression || @@ -77,7 +83,6 @@ bool getIsPositioned(const base::Base& node) { ndk == ndkUpdateExpression || ndk == ndkYieldExpression || ndk == ndkProperty || - ndk == ndkAssignmentProperty || ndk == ndkSpreadElement || ndk == ndkSuper || ndk == ndkTemplateElement || @@ -116,7 +121,8 @@ bool getIsPositioned(const base::Base& node) { ndk == ndkExportSpecifier || ndk == ndkImportDefaultSpecifier || ndk == ndkImportNamespaceSpecifier || - ndk == ndkImportSpecifier; + ndk == ndkImportSpecifier || + ndk == ndkPropertyDefinition; } bool getIsProgram(const base::Base& node) { @@ -216,16 +222,16 @@ bool getIsAssignmentExpression(const base::Base& node) { ndk == ndkAssignmentExpression; } -bool getIsAssignmentProperty(const base::Base& node) { +bool getIsAwaitExpression(const base::Base& node) { NodeKind ndk = node.getNodeKind(); return - ndk == ndkAssignmentProperty; + ndk == ndkAwaitExpression; } -bool getIsAwaitExpression(const base::Base& node) { +bool getIsBigIntLiteral(const base::Base& node) { NodeKind ndk = node.getNodeKind(); return - ndk == ndkAwaitExpression; + ndk == ndkBigIntLiteral; } bool getIsBinaryExpression(const base::Base& node) { @@ -246,6 +252,20 @@ bool getIsCallExpression(const base::Base& node) { ndk == ndkCallExpression; } +bool getIsChainElement(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkChainElement || + ndk == ndkCallExpression || + ndk == ndkMemberExpression; +} + +bool getIsChainExpression(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkChainExpression; +} + bool getIsClassExpression(const base::Base& node) { NodeKind ndk = node.getNodeKind(); return @@ -268,10 +288,13 @@ bool getIsExpression(const base::Base& node) { ndk == ndkAwaitExpression || ndk == ndkBinaryExpression || ndk == ndkCallExpression || + ndk == ndkChainExpression || ndk == ndkClassExpression || ndk == ndkConditionalExpression || ndk == ndkFunctionExpression || ndk == ndkIdentifier || + ndk == ndkImportExpression || + ndk == ndkBigIntLiteral || ndk == ndkBooleanLiteral || ndk == ndkNullLiteral || ndk == ndkNumberLiteral || @@ -303,10 +326,17 @@ bool getIsIdentifier(const base::Base& node) { ndk == ndkIdentifier; } +bool getIsImportExpression(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkImportExpression; +} + bool getIsLiteral(const base::Base& node) { NodeKind ndk = node.getNodeKind(); return ndk == ndkLiteral || + ndk == ndkBigIntLiteral || ndk == ndkBooleanLiteral || ndk == ndkNullLiteral || ndk == ndkNumberLiteral || @@ -356,11 +386,16 @@ bool getIsObjectExpression(const base::Base& node) { ndk == ndkObjectExpression; } +bool getIsPrivateIdentifier(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkPrivateIdentifier; +} + bool getIsProperty(const base::Base& node) { NodeKind ndk = node.getNodeKind(); return - ndk == ndkProperty || - ndk == ndkAssignmentProperty; + ndk == ndkProperty; } bool getIsRegExpLiteral(const base::Base& node) { @@ -694,6 +729,12 @@ bool getIsModuleSpecifier(const base::Base& node) { ndk == ndkImportSpecifier; } +bool getIsPropertyDefinition(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkPropertyDefinition; +} + bool getIsComposite(const base::Base& node) { return !getIsNotComposite(node); } @@ -703,7 +744,10 @@ bool getIsNotComposite(const base::Base& node) { return ndk == ndkComment || ndk == ndkIdentifier || + ndk == ndkPrivateIdentifier || ndk == ndkModuleDeclaration || + ndk == ndkChainElement || + ndk == ndkBigIntLiteral || ndk == ndkBooleanLiteral || ndk == ndkNullLiteral || ndk == ndkNumberLiteral || @@ -768,15 +812,20 @@ bool getIsBaseClassKind(NodeKind what, NodeKind base) { getIsBaseClassKind(ndkFunction, base); case ndkAssignmentExpression: return getIsBaseClassKind(ndkExpression, base); - case ndkAssignmentProperty: - return getIsBaseClassKind(ndkProperty, base); case ndkAwaitExpression: return getIsBaseClassKind(ndkExpression, base); + case ndkBigIntLiteral: + return getIsBaseClassKind(ndkLiteral, base); case ndkBinaryExpression: return getIsBaseClassKind(ndkExpression, base); case ndkBooleanLiteral: return getIsBaseClassKind(ndkLiteral, base); case ndkCallExpression: + return getIsBaseClassKind(ndkExpression, base) || + getIsBaseClassKind(ndkChainElement, base); + case ndkChainElement: + return getIsBaseClassKind(ndkPositioned, base); + case ndkChainExpression: return getIsBaseClassKind(ndkExpression, base); case ndkClassExpression: return getIsBaseClassKind(ndkExpression, base) || @@ -792,6 +841,8 @@ bool getIsBaseClassKind(NodeKind what, NodeKind base) { return getIsBaseClassKind(ndkExpression, base) || getIsBaseClassKind(ndkPattern, base) || getIsBaseClassKind(ndkNamed, base); + case ndkImportExpression: + return getIsBaseClassKind(ndkExpression, base); case ndkLiteral: return getIsBaseClassKind(ndkPositioned, base) || getIsBaseClassKind(ndkExpression, base); @@ -799,7 +850,8 @@ bool getIsBaseClassKind(NodeKind what, NodeKind base) { return getIsBaseClassKind(ndkExpression, base); case ndkMemberExpression: return getIsBaseClassKind(ndkExpression, base) || - getIsBaseClassKind(ndkPattern, base); + getIsBaseClassKind(ndkPattern, base) || + getIsBaseClassKind(ndkChainElement, base); case ndkMetaProperty: return getIsBaseClassKind(ndkExpression, base); case ndkNewExpression: @@ -810,6 +862,9 @@ bool getIsBaseClassKind(NodeKind what, NodeKind base) { return getIsBaseClassKind(ndkLiteral, base); case ndkObjectExpression: return getIsBaseClassKind(ndkExpression, base); + case ndkPrivateIdentifier: + return getIsBaseClassKind(ndkPositioned, base) || + getIsBaseClassKind(ndkNamed, base); case ndkProperty: return getIsBaseClassKind(ndkPositioned, base); case ndkRegExpLiteral: @@ -908,6 +963,8 @@ bool getIsBaseClassKind(NodeKind what, NodeKind base) { return getIsBaseClassKind(ndkPositioned, base); case ndkModuleSpecifier: return getIsBaseClassKind(ndkPositioned, base); + case ndkPropertyDefinition: + return getIsBaseClassKind(ndkPositioned, base); default: return false; } @@ -929,6 +986,9 @@ const std::string toString(AssignmentOperator kind) { case asoBitwiseXor: return "asoBitwiseXor"; case asoBitwiseAnd: return "asoBitwiseAnd"; case asoExponentiation: return "asoExponentiation"; + case asoAnd: return "asoAnd"; + case asoOr: return "asoOr"; + case asoNullishCoalescing: return "asoNullishCoalescing"; default: throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); } } @@ -990,6 +1050,7 @@ const std::string toString(LogicalOperator kind) { switch (kind) { case looAnd: return "looAnd"; case looOr: return "looOr"; + case looNullishCoalescing: return "looNullishCoalescing"; default: throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); } } @@ -1063,16 +1124,19 @@ const std::string toString(NodeKind kind) { case ndkArrayExpression: return "ndkArrayExpression"; case ndkArrowFunctionExpression: return "ndkArrowFunctionExpression"; case ndkAssignmentExpression: return "ndkAssignmentExpression"; - case ndkAssignmentProperty: return "ndkAssignmentProperty"; case ndkAwaitExpression: return "ndkAwaitExpression"; + case ndkBigIntLiteral: return "ndkBigIntLiteral"; case ndkBinaryExpression: return "ndkBinaryExpression"; case ndkBooleanLiteral: return "ndkBooleanLiteral"; case ndkCallExpression: return "ndkCallExpression"; + case ndkChainElement: return "ndkChainElement"; + case ndkChainExpression: return "ndkChainExpression"; case ndkClassExpression: return "ndkClassExpression"; case ndkConditionalExpression: return "ndkConditionalExpression"; case ndkExpression: return "ndkExpression"; case ndkFunctionExpression: return "ndkFunctionExpression"; case ndkIdentifier: return "ndkIdentifier"; + case ndkImportExpression: return "ndkImportExpression"; case ndkLiteral: return "ndkLiteral"; case ndkLogicalExpression: return "ndkLogicalExpression"; case ndkMemberExpression: return "ndkMemberExpression"; @@ -1081,6 +1145,7 @@ const std::string toString(NodeKind kind) { case ndkNullLiteral: return "ndkNullLiteral"; case ndkNumberLiteral: return "ndkNumberLiteral"; case ndkObjectExpression: return "ndkObjectExpression"; + case ndkPrivateIdentifier: return "ndkPrivateIdentifier"; case ndkProperty: return "ndkProperty"; case ndkRegExpLiteral: return "ndkRegExpLiteral"; case ndkSequenceExpression: return "ndkSequenceExpression"; @@ -1130,6 +1195,7 @@ const std::string toString(NodeKind kind) { case ndkImportSpecifier: return "ndkImportSpecifier"; case ndkMethodDefinition: return "ndkMethodDefinition"; case ndkModuleSpecifier: return "ndkModuleSpecifier"; + case ndkPropertyDefinition: return "ndkPropertyDefinition"; default: throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); } } @@ -1140,6 +1206,7 @@ const std::string toString(EdgeKind kind) { case edkProgram_HasBody: return "edkProgram_HasBody"; case edkSystem_HasPrograms: return "edkSystem_HasPrograms"; case edkExportAllDeclaration_HasSource: return "edkExportAllDeclaration_HasSource"; + case edkExportAllDeclaration_HasExported: return "edkExportAllDeclaration_HasExported"; case edkExportDefaultDeclaration_HasDeclaration: return "edkExportDefaultDeclaration_HasDeclaration"; case edkExportNamedDeclaration_HasDeclaration: return "edkExportNamedDeclaration_HasDeclaration"; case edkExportNamedDeclaration_HasSpecifiers: return "edkExportNamedDeclaration_HasSpecifiers"; @@ -1158,10 +1225,12 @@ const std::string toString(EdgeKind kind) { case edkCallExpression_HasCallee: return "edkCallExpression_HasCallee"; case edkCallExpression_HasArguments: return "edkCallExpression_HasArguments"; case edkCallExpression_Calls: return "edkCallExpression_Calls"; + case edkChainExpression_HasExpression: return "edkChainExpression_HasExpression"; case edkConditionalExpression_HasAlternate: return "edkConditionalExpression_HasAlternate"; case edkConditionalExpression_HasConsequent: return "edkConditionalExpression_HasConsequent"; case edkConditionalExpression_HasTest: return "edkConditionalExpression_HasTest"; case edkIdentifier_RefersTo: return "edkIdentifier_RefersTo"; + case edkImportExpression_HasSource: return "edkImportExpression_HasSource"; case edkLogicalExpression_HasLeft: return "edkLogicalExpression_HasLeft"; case edkLogicalExpression_HasRight: return "edkLogicalExpression_HasRight"; case edkMemberExpression_HasProperty: return "edkMemberExpression_HasProperty"; @@ -1231,6 +1300,8 @@ const std::string toString(EdgeKind kind) { case edkMethodDefinition_HasKey: return "edkMethodDefinition_HasKey"; case edkMethodDefinition_HasValue: return "edkMethodDefinition_HasValue"; case edkModuleSpecifier_HasLocal: return "edkModuleSpecifier_HasLocal"; + case edkPropertyDefinition_HasKey: return "edkPropertyDefinition_HasKey"; + case edkPropertyDefinition_HasValue: return "edkPropertyDefinition_HasValue"; default: throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); } } diff --git a/lib/javascript/src/Factory.cpp b/lib/javascript/src/Factory.cpp index fb7a656..9e317f2 100644 --- a/lib/javascript/src/Factory.cpp +++ b/lib/javascript/src/Factory.cpp @@ -565,14 +565,14 @@ bool Factory::getExistsReverseEdges() const { ap.run(*this, vas); unsigned long totalMemUsage = 0; /* it is the sum of memory of nodes */ common::WriteMsg::write(common::WriteMsg::mlNormal, "Nodes,All,This,Obj Size,Used Mem,Used Mem\n"); - for (int i = 0; i < 86; ++i) { + for (int i = 0; i < 91; ++i) { totalMemUsage += vas.nodeStatSimple[i] * vas.nodeSizes[i]; common::WriteMsg::write(common::WriteMsg::mlNormal, "%s,%d,%d,%d,%d,%d\n", vas.nodeNames[i], vas.nodeStatParent[i], vas.nodeStatSimple[i], vas.nodeSizes[i], vas.nodeStatSimple[i] * vas.nodeSizes[i], vas.nodeStatSimple[i] * vas.nodeSizes[i] / 1024); } common::WriteMsg::write(common::WriteMsg::mlNormal, "\n"); common::WriteMsg::write(common::WriteMsg::mlNormal, "Memory used by nodes: %d (%d KB)\n\n", totalMemUsage, totalMemUsage ); if (edgeStat) { common::WriteMsg::write(common::WriteMsg::mlNormal, "Edges,Cardinality\n"); - for (int i = 0; i < 95; ++i) + for (int i = 0; i < 100; ++i) common::WriteMsg::write(common::WriteMsg::mlNormal, "%s,%d\n", Common::toString((EdgeKind)i).c_str(), vas.edgeStat[i]); common::WriteMsg::write(common::WriteMsg::mlNormal, "\n\n"); } @@ -604,15 +604,18 @@ base::Base* Factory::createNode(NodeKind kind) { case ndkArrayExpression: p = new expression::ArrayExpression(id, this); break; case ndkArrowFunctionExpression: p = new expression::ArrowFunctionExpression(id, this); break; case ndkAssignmentExpression: p = new expression::AssignmentExpression(id, this); break; - case ndkAssignmentProperty: p = new expression::AssignmentProperty(id, this); break; case ndkAwaitExpression: p = new expression::AwaitExpression(id, this); break; + case ndkBigIntLiteral: p = new expression::BigIntLiteral(id, this); break; case ndkBinaryExpression: p = new expression::BinaryExpression(id, this); break; case ndkBooleanLiteral: p = new expression::BooleanLiteral(id, this); break; case ndkCallExpression: p = new expression::CallExpression(id, this); break; + case ndkChainElement: p = new expression::ChainElement(id, this); break; + case ndkChainExpression: p = new expression::ChainExpression(id, this); break; case ndkClassExpression: p = new expression::ClassExpression(id, this); break; case ndkConditionalExpression: p = new expression::ConditionalExpression(id, this); break; case ndkFunctionExpression: p = new expression::FunctionExpression(id, this); break; case ndkIdentifier: p = new expression::Identifier(id, this); break; + case ndkImportExpression: p = new expression::ImportExpression(id, this); break; case ndkLogicalExpression: p = new expression::LogicalExpression(id, this); break; case ndkMemberExpression: p = new expression::MemberExpression(id, this); break; case ndkMetaProperty: p = new expression::MetaProperty(id, this); break; @@ -620,6 +623,7 @@ base::Base* Factory::createNode(NodeKind kind) { case ndkNullLiteral: p = new expression::NullLiteral(id, this); break; case ndkNumberLiteral: p = new expression::NumberLiteral(id, this); break; case ndkObjectExpression: p = new expression::ObjectExpression(id, this); break; + case ndkPrivateIdentifier: p = new expression::PrivateIdentifier(id, this); break; case ndkProperty: p = new expression::Property(id, this); break; case ndkRegExpLiteral: p = new expression::RegExpLiteral(id, this); break; case ndkSequenceExpression: p = new expression::SequenceExpression(id, this); break; @@ -664,6 +668,7 @@ base::Base* Factory::createNode(NodeKind kind) { case ndkImportNamespaceSpecifier: p = new structure::ImportNamespaceSpecifier(id, this); break; case ndkImportSpecifier: p = new structure::ImportSpecifier(id, this); break; case ndkMethodDefinition: p = new structure::MethodDefinition(id, this); break; + case ndkPropertyDefinition: p = new structure::PropertyDefinition(id, this); break; default: throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); } @@ -700,15 +705,18 @@ base::Base& Factory::createNode(NodeKind kind, NodeId i) { case ndkArrayExpression: p = new expression::ArrayExpression(i,this); break; case ndkArrowFunctionExpression: p = new expression::ArrowFunctionExpression(i,this); break; case ndkAssignmentExpression: p = new expression::AssignmentExpression(i,this); break; - case ndkAssignmentProperty: p = new expression::AssignmentProperty(i,this); break; case ndkAwaitExpression: p = new expression::AwaitExpression(i,this); break; + case ndkBigIntLiteral: p = new expression::BigIntLiteral(i,this); break; case ndkBinaryExpression: p = new expression::BinaryExpression(i,this); break; case ndkBooleanLiteral: p = new expression::BooleanLiteral(i,this); break; case ndkCallExpression: p = new expression::CallExpression(i,this); break; + case ndkChainElement: p = new expression::ChainElement(i,this); break; + case ndkChainExpression: p = new expression::ChainExpression(i,this); break; case ndkClassExpression: p = new expression::ClassExpression(i,this); break; case ndkConditionalExpression: p = new expression::ConditionalExpression(i,this); break; case ndkFunctionExpression: p = new expression::FunctionExpression(i,this); break; case ndkIdentifier: p = new expression::Identifier(i,this); break; + case ndkImportExpression: p = new expression::ImportExpression(i,this); break; case ndkLogicalExpression: p = new expression::LogicalExpression(i,this); break; case ndkMemberExpression: p = new expression::MemberExpression(i,this); break; case ndkMetaProperty: p = new expression::MetaProperty(i,this); break; @@ -716,6 +724,7 @@ base::Base& Factory::createNode(NodeKind kind, NodeId i) { case ndkNullLiteral: p = new expression::NullLiteral(i,this); break; case ndkNumberLiteral: p = new expression::NumberLiteral(i,this); break; case ndkObjectExpression: p = new expression::ObjectExpression(i,this); break; + case ndkPrivateIdentifier: p = new expression::PrivateIdentifier(i,this); break; case ndkProperty: p = new expression::Property(i,this); break; case ndkRegExpLiteral: p = new expression::RegExpLiteral(i,this); break; case ndkSequenceExpression: p = new expression::SequenceExpression(i,this); break; @@ -760,6 +769,7 @@ base::Base& Factory::createNode(NodeKind kind, NodeId i) { case ndkImportNamespaceSpecifier: p = new structure::ImportNamespaceSpecifier(i,this); break; case ndkImportSpecifier: p = new structure::ImportSpecifier(i,this); break; case ndkMethodDefinition: p = new structure::MethodDefinition(i,this); break; + case ndkPropertyDefinition: p = new structure::PropertyDefinition(i,this); break; default: throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); } @@ -838,14 +848,14 @@ base::Base& Factory::createNode(NodeKind kind, NodeId i) { return dynamic_cast ( createNode(ndkAssignmentExpression)); } - expression::AssignmentProperty* Factory::createAssignmentPropertyNode(){ - return dynamic_cast ( createNode(ndkAssignmentProperty)); - } - expression::AwaitExpression* Factory::createAwaitExpressionNode(){ return dynamic_cast ( createNode(ndkAwaitExpression)); } + expression::BigIntLiteral* Factory::createBigIntLiteralNode(){ + return dynamic_cast ( createNode(ndkBigIntLiteral)); + } + expression::BinaryExpression* Factory::createBinaryExpressionNode(){ return dynamic_cast ( createNode(ndkBinaryExpression)); } @@ -858,6 +868,14 @@ base::Base& Factory::createNode(NodeKind kind, NodeId i) { return dynamic_cast ( createNode(ndkCallExpression)); } + expression::ChainElement* Factory::createChainElementNode(){ + return dynamic_cast ( createNode(ndkChainElement)); + } + + expression::ChainExpression* Factory::createChainExpressionNode(){ + return dynamic_cast ( createNode(ndkChainExpression)); + } + expression::ClassExpression* Factory::createClassExpressionNode(){ return dynamic_cast ( createNode(ndkClassExpression)); } @@ -874,6 +892,10 @@ base::Base& Factory::createNode(NodeKind kind, NodeId i) { return dynamic_cast ( createNode(ndkIdentifier)); } + expression::ImportExpression* Factory::createImportExpressionNode(){ + return dynamic_cast ( createNode(ndkImportExpression)); + } + expression::LogicalExpression* Factory::createLogicalExpressionNode(){ return dynamic_cast ( createNode(ndkLogicalExpression)); } @@ -902,6 +924,10 @@ base::Base& Factory::createNode(NodeKind kind, NodeId i) { return dynamic_cast ( createNode(ndkObjectExpression)); } + expression::PrivateIdentifier* Factory::createPrivateIdentifierNode(){ + return dynamic_cast ( createNode(ndkPrivateIdentifier)); + } + expression::Property* Factory::createPropertyNode(){ return dynamic_cast ( createNode(ndkProperty)); } @@ -1078,6 +1104,10 @@ base::Base& Factory::createNode(NodeKind kind, NodeId i) { return dynamic_cast ( createNode(ndkMethodDefinition)); } + structure::PropertyDefinition* Factory::createPropertyDefinitionNode(){ + return dynamic_cast ( createNode(ndkPropertyDefinition)); + } + void Factory::printNodeSizes() { printf("base::Comment node: %dbyte(s)\n",(int)sizeof(base::Comment)); printf("base::Program node: %dbyte(s)\n",(int)sizeof(base::Program)); @@ -1094,15 +1124,18 @@ base::Base& Factory::createNode(NodeKind kind, NodeId i) { printf("expression::ArrayExpression node: %dbyte(s)\n",(int)sizeof(expression::ArrayExpression)); printf("expression::ArrowFunctionExpression node: %dbyte(s)\n",(int)sizeof(expression::ArrowFunctionExpression)); printf("expression::AssignmentExpression node: %dbyte(s)\n",(int)sizeof(expression::AssignmentExpression)); - printf("expression::AssignmentProperty node: %dbyte(s)\n",(int)sizeof(expression::AssignmentProperty)); printf("expression::AwaitExpression node: %dbyte(s)\n",(int)sizeof(expression::AwaitExpression)); + printf("expression::BigIntLiteral node: %dbyte(s)\n",(int)sizeof(expression::BigIntLiteral)); printf("expression::BinaryExpression node: %dbyte(s)\n",(int)sizeof(expression::BinaryExpression)); printf("expression::BooleanLiteral node: %dbyte(s)\n",(int)sizeof(expression::BooleanLiteral)); printf("expression::CallExpression node: %dbyte(s)\n",(int)sizeof(expression::CallExpression)); + printf("expression::ChainElement node: %dbyte(s)\n",(int)sizeof(expression::ChainElement)); + printf("expression::ChainExpression node: %dbyte(s)\n",(int)sizeof(expression::ChainExpression)); printf("expression::ClassExpression node: %dbyte(s)\n",(int)sizeof(expression::ClassExpression)); printf("expression::ConditionalExpression node: %dbyte(s)\n",(int)sizeof(expression::ConditionalExpression)); printf("expression::FunctionExpression node: %dbyte(s)\n",(int)sizeof(expression::FunctionExpression)); printf("expression::Identifier node: %dbyte(s)\n",(int)sizeof(expression::Identifier)); + printf("expression::ImportExpression node: %dbyte(s)\n",(int)sizeof(expression::ImportExpression)); printf("expression::LogicalExpression node: %dbyte(s)\n",(int)sizeof(expression::LogicalExpression)); printf("expression::MemberExpression node: %dbyte(s)\n",(int)sizeof(expression::MemberExpression)); printf("expression::MetaProperty node: %dbyte(s)\n",(int)sizeof(expression::MetaProperty)); @@ -1110,6 +1143,7 @@ base::Base& Factory::createNode(NodeKind kind, NodeId i) { printf("expression::NullLiteral node: %dbyte(s)\n",(int)sizeof(expression::NullLiteral)); printf("expression::NumberLiteral node: %dbyte(s)\n",(int)sizeof(expression::NumberLiteral)); printf("expression::ObjectExpression node: %dbyte(s)\n",(int)sizeof(expression::ObjectExpression)); + printf("expression::PrivateIdentifier node: %dbyte(s)\n",(int)sizeof(expression::PrivateIdentifier)); printf("expression::Property node: %dbyte(s)\n",(int)sizeof(expression::Property)); printf("expression::RegExpLiteral node: %dbyte(s)\n",(int)sizeof(expression::RegExpLiteral)); printf("expression::SequenceExpression node: %dbyte(s)\n",(int)sizeof(expression::SequenceExpression)); @@ -1154,6 +1188,7 @@ base::Base& Factory::createNode(NodeKind kind, NodeId i) { printf("structure::ImportNamespaceSpecifier node: %dbyte(s)\n",(int)sizeof(structure::ImportNamespaceSpecifier)); printf("structure::ImportSpecifier node: %dbyte(s)\n",(int)sizeof(structure::ImportSpecifier)); printf("structure::MethodDefinition node: %dbyte(s)\n",(int)sizeof(structure::MethodDefinition)); + printf("structure::PropertyDefinition node: %dbyte(s)\n",(int)sizeof(structure::PropertyDefinition)); } }}} diff --git a/lib/javascript/src/ListIterator.cpp b/lib/javascript/src/ListIterator.cpp index 46bd390..ee29c47 100644 --- a/lib/javascript/src/ListIterator.cpp +++ b/lib/javascript/src/ListIterator.cpp @@ -207,6 +207,5 @@ namespace columbus { namespace javascript { namespace asg { template class ListIterator; template class ListIterator; template class ListIterator; - template class ListIterator; }}} diff --git a/lib/javascript/src/ReverseEdges.cpp b/lib/javascript/src/ReverseEdges.cpp index 5894a52..71d86a8 100644 --- a/lib/javascript/src/ReverseEdges.cpp +++ b/lib/javascript/src/ReverseEdges.cpp @@ -103,7 +103,7 @@ void ReverseEdges::getAllExistingEdges(NodeId id, std::set& edges) con void ReverseEdges::getAllPossibleEdges(NodeKind kind, std::vector& edges) const { edges.clear(); - for (int i = 0; i < 95; ++i) { + for (int i = 0; i < 100; ++i) { if (possibleEdges[kind][i]) { edges.push_back(static_cast(i)); } @@ -112,7 +112,7 @@ void ReverseEdges::getAllPossibleEdges(NodeKind kind, std::vector& edg void ReverseEdges::getAllPossibleEdges(NodeKind kind, std::set& edges) const { edges.clear(); - for (int i = 0; i < 95; ++i) { + for (int i = 0; i < 100; ++i) { if (possibleEdges[kind][i]) { edges.insert(static_cast(i)); } @@ -188,93 +188,98 @@ void ReverseEdges::removeEdge(NodeId from, NodeId to, EdgeKind edge) { itFind->second.erase( find(itFind->second.begin(),itFind->second.end(), to)); } -bool ReverseEdges::possibleEdges[86][95] = { // nodes x edges - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,0,0,1,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,1,1,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,1,0}, - {0,0,0,0,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,1,0,1,1,1,0,1}, - {0,0,0,1,1,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,0,1,0,1,1,1,1,1,0,1,0,0,0,0,0,1,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,1,1,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,1,1,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,1,1,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,1,1,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0,1,0,0,1,1,0,1,0,0,0,0,1,0,0,0,1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} +bool ReverseEdges::possibleEdges[91][100] = { // nodes x edges + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,0,0,1,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,1,0,1,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,1,0,1,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,1,0,1,1}, + {0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,1,0,1,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,0,1,0,1,1,1,1,1,0,1,0,0,0,0,0,1,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,1,0,1,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,1,0,1,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,1,0,1,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,1,0,1,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1}, + {0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0,1,0,0,1,1,0,1,0,0,0,0,1,0,0,0,1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0} }; diff --git a/lib/javascript/src/algorithms/AlgorithmPreorder.cpp b/lib/javascript/src/algorithms/AlgorithmPreorder.cpp index 04b0613..f24c062 100644 --- a/lib/javascript/src/algorithms/AlgorithmPreorder.cpp +++ b/lib/javascript/src/algorithms/AlgorithmPreorder.cpp @@ -43,7 +43,7 @@ AlgorithmPreorder::AlgorithmPreorder() fact(NULL), traversaldCrossEdges() { - memset(traversaldCrossEdges,false,sizeof(bool)*95); + memset(traversaldCrossEdges,false,sizeof(bool)*100); } AlgorithmPreorder::~AlgorithmPreorder() { @@ -425,6 +425,30 @@ void AlgorithmPreorder::visitAllEdges(const declaration::ExportAllDeclaration& n if(needPreorderStop) return; } + + // edge: hasExported + genNodePtr = node.getExported() ; + if (genNodePtr) { + const expression::Identifier& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitExportAllDeclaration_HasExported(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + endNodeRef.accept(*this); + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndExportAllDeclaration_HasExported(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } } void AlgorithmPreorder::visit(const declaration::ExportAllDeclaration& node, bool callFirst /*= true*/){ @@ -1147,11 +1171,40 @@ void AlgorithmPreorder::visit(const expression::AssignmentExpression& node, bool clearStoppedVisitors(); } -void AlgorithmPreorder::visitAllEdges(const expression::AssignmentProperty& node, bool callFirst /*= true*/){ - visitAllEdges(dynamic_cast(node),false); +void AlgorithmPreorder::visitAllEdges(const expression::AwaitExpression& node, bool callFirst /*= true*/){ + if (callFirst) + visitAllEdges(dynamic_cast(node),false); + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasArgument + genNodePtr = node.getArgument() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitAwaitExpression_HasArgument(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + endNodeRef.accept(*this); + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndAwaitExpression_HasArgument(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } } -void AlgorithmPreorder::visit(const expression::AssignmentProperty& node, bool callFirst /*= true*/){ +void AlgorithmPreorder::visit(const expression::AwaitExpression& node, bool callFirst /*= true*/){ #ifdef DEBUG_PREORDER std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; #endif @@ -1184,40 +1237,13 @@ void AlgorithmPreorder::visit(const expression::AssignmentProperty& node, bool c clearStoppedVisitors(); } -void AlgorithmPreorder::visitAllEdges(const expression::AwaitExpression& node, bool callFirst /*= true*/){ +void AlgorithmPreorder::visitAllEdges(const expression::BigIntLiteral& node, bool callFirst /*= true*/){ if (callFirst) visitAllEdges(dynamic_cast(node),false); - visitAllEdges(dynamic_cast(node),false); - - std::list::iterator itVisitors; - - const base::Base* genNodePtr; - // edge: hasArgument - genNodePtr = node.getArgument() ; - if (genNodePtr) { - const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); - for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { - (*itVisitors)->visitAwaitExpression_HasArgument(node, endNodeRef); - } - - clearStoppedVisitors(); - if(needPreorderStop) - return; - - if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { - endNodeRef.accept(*this); - } - for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { - (*itVisitors)->visitEndAwaitExpression_HasArgument(node, endNodeRef); - } - - clearStoppedVisitors(); - if(needPreorderStop) - return; - } + visitAllEdges(dynamic_cast(node),false); } -void AlgorithmPreorder::visit(const expression::AwaitExpression& node, bool callFirst /*= true*/){ +void AlgorithmPreorder::visit(const expression::BigIntLiteral& node, bool callFirst /*= true*/){ #ifdef DEBUG_PREORDER std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; #endif @@ -1261,7 +1287,7 @@ void AlgorithmPreorder::visitAllEdges(const expression::BinaryExpression& node, // edge: hasLeft genNodePtr = node.getLeft() ; if (genNodePtr) { - const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + const base::Positioned& endNodeRef = dynamic_cast(*genNodePtr); for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { (*itVisitors)->visitBinaryExpression_HasLeft(node, endNodeRef); } @@ -1383,6 +1409,7 @@ void AlgorithmPreorder::visitAllEdges(const expression::CallExpression& node, bo if (callFirst) visitAllEdges(dynamic_cast(node),false); visitAllEdges(dynamic_cast(node),false); + visitAllEdges(dynamic_cast(node),false); std::list::iterator itVisitors; @@ -1498,6 +1525,110 @@ void AlgorithmPreorder::visit(const expression::CallExpression& node, bool callF clearStoppedVisitors(); } +void AlgorithmPreorder::visitAllEdges(const expression::ChainElement& node, bool callFirst /*= true*/){ + if (callFirst) + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visit(const expression::ChainElement& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::ChainExpression& node, bool callFirst /*= true*/){ + if (callFirst) + visitAllEdges(dynamic_cast(node),false); + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasExpression + genNodePtr = node.getExpression() ; + if (genNodePtr) { + const expression::ChainElement& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitChainExpression_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + endNodeRef.accept(*this); + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndChainExpression_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const expression::ChainExpression& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + void AlgorithmPreorder::visitAllEdges(const expression::ClassExpression& node, bool callFirst /*= true*/){ if (callFirst) visitAllEdges(dynamic_cast(node),false); @@ -1772,6 +1903,72 @@ void AlgorithmPreorder::visit(const expression::Identifier& node, bool callFirst clearStoppedVisitors(); } +void AlgorithmPreorder::visitAllEdges(const expression::ImportExpression& node, bool callFirst /*= true*/){ + if (callFirst) + visitAllEdges(dynamic_cast(node),false); + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasSource + genNodePtr = node.getSource() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitImportExpression_HasSource(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + endNodeRef.accept(*this); + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndImportExpression_HasSource(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const expression::ImportExpression& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + void AlgorithmPreorder::visitAllEdges(const expression::Literal& node, bool callFirst /*= true*/){ if (callFirst) visitAllEdges(dynamic_cast(node),false); @@ -1873,6 +2070,7 @@ void AlgorithmPreorder::visitAllEdges(const expression::MemberExpression& node, visitAllEdges(dynamic_cast(node),false); visitAllEdges(dynamic_cast(node),false); visitAllEdges(dynamic_cast(node),false); + visitAllEdges(dynamic_cast(node),false); std::list::iterator itVisitors; @@ -1880,7 +2078,7 @@ void AlgorithmPreorder::visitAllEdges(const expression::MemberExpression& node, // edge: hasProperty genNodePtr = node.getProperty() ; if (genNodePtr) { - const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + const base::Positioned& endNodeRef = dynamic_cast(*genNodePtr); for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { (*itVisitors)->visitMemberExpression_HasProperty(node, endNodeRef); } @@ -2310,6 +2508,45 @@ void AlgorithmPreorder::visit(const expression::ObjectExpression& node, bool cal clearStoppedVisitors(); } +void AlgorithmPreorder::visitAllEdges(const expression::PrivateIdentifier& node, bool callFirst /*= true*/){ + if (callFirst) + visitAllEdges(dynamic_cast(node),false); + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visit(const expression::PrivateIdentifier& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + void AlgorithmPreorder::visitAllEdges(const expression::Property& node, bool callFirst /*= true*/){ visitAllEdges(dynamic_cast(node),false); @@ -5148,8 +5385,8 @@ void AlgorithmPreorder::visitAllEdges(const structure::ClassBody& node, bool cal std::list::iterator itVisitors; // edge: hasBody - for (ListIterator it = node.getBodyListIteratorBegin(); it != node.getBodyListIteratorEnd(); ++it) { - const structure::MethodDefinition& endNodeRef = *it; + for (ListIterator it = node.getBodyListIteratorBegin(); it != node.getBodyListIteratorEnd(); ++it) { + const base::Positioned& endNodeRef = *it; for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { (*itVisitors)->visitClassBody_HasBody(node, endNodeRef); } @@ -5419,7 +5656,7 @@ void AlgorithmPreorder::visitAllEdges(const structure::MethodDefinition& node, b // edge: hasKey genNodePtr = node.getKey() ; if (genNodePtr) { - const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + const base::Positioned& endNodeRef = dynamic_cast(*genNodePtr); for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { (*itVisitors)->visitMethodDefinition_HasKey(node, endNodeRef); } @@ -5529,6 +5766,94 @@ void AlgorithmPreorder::visitAllEdges(const structure::ModuleSpecifier& node, bo } } +void AlgorithmPreorder::visitAllEdges(const structure::PropertyDefinition& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasKey + genNodePtr = node.getKey() ; + if (genNodePtr) { + const base::Positioned& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitPropertyDefinition_HasKey(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + endNodeRef.accept(*this); + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndPropertyDefinition_HasKey(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasValue + genNodePtr = node.getValue() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitPropertyDefinition_HasValue(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + endNodeRef.accept(*this); + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndPropertyDefinition_HasValue(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const structure::PropertyDefinition& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + void AlgorithmPreorder::startPreorder(){ if (!fact){ diff --git a/lib/javascript/src/declaration/ExportAllDeclaration.cpp b/lib/javascript/src/declaration/ExportAllDeclaration.cpp index f05d8b4..5911822 100644 --- a/lib/javascript/src/declaration/ExportAllDeclaration.cpp +++ b/lib/javascript/src/declaration/ExportAllDeclaration.cpp @@ -36,7 +36,8 @@ namespace declaration { ExportAllDeclaration::ExportAllDeclaration(NodeId _id, Factory *_factory) : Positioned(_id, _factory), Declaration(_id, _factory), - m_hasSource(0) + m_hasSource(0), + m_hasExported(0) { } @@ -45,6 +46,7 @@ namespace declaration { void ExportAllDeclaration::prepareDelete(bool tryOnVirtualParent){ removeSource(); + removeExported(); if (tryOnVirtualParent) { base::Positioned::prepareDelete(false); } @@ -65,11 +67,24 @@ namespace declaration { return _node; } + expression::Identifier* ExportAllDeclaration::getExported() const { + expression::Identifier *_node = NULL; + if (m_hasExported != 0) + _node = dynamic_cast(factory->getPointer(m_hasExported)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + bool ExportAllDeclaration::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { switch (edgeKind) { case edkExportAllDeclaration_HasSource: setSource(edgeEnd); return true; + case edkExportAllDeclaration_HasExported: + setExported(edgeEnd); + return true; default: break; } @@ -89,6 +104,9 @@ namespace declaration { case edkExportAllDeclaration_HasSource: removeSource(); return true; + case edkExportAllDeclaration_HasExported: + removeExported(); + return true; default: break; } @@ -149,6 +167,52 @@ namespace declaration { m_hasSource = 0; } + void ExportAllDeclaration::setExported(NodeId _id) { + expression::Identifier *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasExported) { + removeParentEdge(m_hasExported); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExported, m_id, edkExportAllDeclaration_HasExported); + } + m_hasExported = _node->getId(); + if (m_hasExported != 0) + setParentEdge(factory->getPointer(m_hasExported), edkExportAllDeclaration_HasExported); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasExported, this->getId(), edkExportAllDeclaration_HasExported); + } else { + if (m_hasExported) { + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void ExportAllDeclaration::setExported(expression::Identifier *_node) { + if (_node == NULL) + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setExported(_node->getId()); + } + + void ExportAllDeclaration::removeExported() { + if (m_hasExported) { + removeParentEdge(m_hasExported); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExported, m_id, edkExportAllDeclaration_HasExported); + } + m_hasExported = 0; + } + void ExportAllDeclaration::accept(Visitor &visitor) const { visitor.visit(*this); } @@ -193,6 +257,7 @@ namespace declaration { Declaration::save(binIo,false); binIo.writeUInt4(m_hasSource); + binIo.writeUInt4(m_hasExported); } @@ -206,6 +271,10 @@ namespace declaration { if (m_hasSource != 0) setParentEdge(factory->getPointer(m_hasSource),edkExportAllDeclaration_HasSource); + m_hasExported = binIo.readUInt4(); + if (m_hasExported != 0) + setParentEdge(factory->getPointer(m_hasExported),edkExportAllDeclaration_HasExported); + } diff --git a/lib/javascript/src/expression/AssignmentProperty.cpp b/lib/javascript/src/expression/AssignmentProperty.cpp deleted file mode 100644 index 2344a06..0000000 --- a/lib/javascript/src/expression/AssignmentProperty.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - * This file is part of OpenStaticAnalyzer. - * - * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged - * - * Licensed under Version 1.2 of the EUPL (the "Licence"); - * - * You may not use this work except in compliance with the Licence. - * - * You may obtain a copy of the Licence in the LICENSE file or at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ - -#include "javascript/inc/javascript.h" -#include "javascript/inc/Common.h" -#include "common/inc/WriteMessage.h" - -#include "javascript/inc/messages.h" -#include -#include -#include "common/inc/math/common.h" - - -namespace columbus { namespace javascript { namespace asg { - -typedef boost::crc_32_type Crc_type; - -namespace expression { - AssignmentProperty::AssignmentProperty(NodeId _id, Factory *_factory) : - Property(_id, _factory) - { - } - - AssignmentProperty::~AssignmentProperty() { - } - - void AssignmentProperty::prepareDelete(bool tryOnVirtualParent){ - expression::Property::prepareDelete(false); - } - - NodeKind AssignmentProperty::getNodeKind() const { - return ndkAssignmentProperty; - } - - bool AssignmentProperty::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { - if (expression::Property::setEdge(edgeKind, edgeEnd, false)) { - return true; - } - return false; - } - - bool AssignmentProperty::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { - if (expression::Property::removeEdge(edgeKind, edgeEnd, false)) { - return true; - } - return false; - } - - void AssignmentProperty::accept(Visitor &visitor) const { - visitor.visit(*this); - } - - void AssignmentProperty::acceptEnd(Visitor &visitor) const { - visitor.visitEnd(*this); - } - - double AssignmentProperty::getSimilarity(const base::Base& base){ - if(base.getNodeKind() == getNodeKind()) { - const AssignmentProperty& node = dynamic_cast(base); - double matchAttrs = 0; - if(node.getKind() == getKind()) ++matchAttrs; - if(node.getMethod() == getMethod()) ++matchAttrs; - if(node.getShorthand() == getShorthand()) ++matchAttrs; - if(node.getComputed() == getComputed()) ++matchAttrs; - return matchAttrs / (4 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; - } else { - return 0.0; - } - } - - void AssignmentProperty::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ - std::map::iterator foundKeyId; - - } - - NodeHashType AssignmentProperty::getHash(std::set& travNodes) const { - if (hashOk) return nodeHashCache; - common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); - if (travNodes.count(getId())>0) { - common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); - return 0; - } - travNodes.insert(getId()); - Crc_type resultHash; - resultHash.process_bytes( "expression::AssignmentProperty", strlen("expression::AssignmentProperty")); - common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); - nodeHashCache = resultHash.checksum(); - hashOk = true; - return nodeHashCache; - } - - void AssignmentProperty::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { - Property::save(binIo,false); - - } - - void AssignmentProperty::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { - Property::load(binIo,false); - - } - - -} - - -}}} diff --git a/lib/javascript/src/expression/BigIntLiteral.cpp b/lib/javascript/src/expression/BigIntLiteral.cpp new file mode 100644 index 0000000..249bc59 --- /dev/null +++ b/lib/javascript/src/expression/BigIntLiteral.cpp @@ -0,0 +1,194 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "javascript/inc/javascript.h" +#include "javascript/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "javascript/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace javascript { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + BigIntLiteral::BigIntLiteral(NodeId _id, Factory *_factory) : + Positioned(_id, _factory), + Literal(_id, _factory), + m_bigint(0) + { + } + + BigIntLiteral::~BigIntLiteral() { + } + + void BigIntLiteral::prepareDelete(bool tryOnVirtualParent){ + if (tryOnVirtualParent) { + base::Positioned::prepareDelete(false); + } + expression::Literal::prepareDelete(false); + } + + NodeKind BigIntLiteral::getNodeKind() const { + return ndkBigIntLiteral; + } + + Key BigIntLiteral::getBigintKey() const { + return m_bigint; + } + + const std::string& BigIntLiteral::getBigint() const { + return factory->getStringTable().get(m_bigint); + } + + void BigIntLiteral::setBigintKey(Key _bigint) { + m_bigint = _bigint; + } + + void BigIntLiteral::setBigint(const std::string& _bigint) { + m_bigint = factory->getStringTable().set(_bigint); + } + + bool BigIntLiteral::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (tryOnVirtualParent) { + if (base::Positioned::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + } + if (expression::Literal::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool BigIntLiteral::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (tryOnVirtualParent) { + if (base::Positioned::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + } + if (expression::Literal::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void BigIntLiteral::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void BigIntLiteral::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double BigIntLiteral::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const BigIntLiteral& node = dynamic_cast(base); + double matchAttrs = 0; + std::string str1, str2; + size_t strMax; + double strSim; + str1 = getRaw(); + str2 = node.getRaw(); + strMax = std::max(str1.size(), str2.size()); + strSim = 1 - ((double)common::math::editDistance(str1, str2) / (strMax > 0 ? strMax : 1)); + if (strSim < Common::SimilarityMinForStrings) + return 0.0; + matchAttrs += strSim; + str1 = getBigint(); + str2 = node.getBigint(); + strMax = std::max(str1.size(), str2.size()); + strSim = 1 - ((double)common::math::editDistance(str1, str2) / (strMax > 0 ? strMax : 1)); + if (strSim < Common::SimilarityMinForStrings) + return 0.0; + matchAttrs += strSim; + return matchAttrs / (2 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void BigIntLiteral::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + foundKeyId = oldAndNewStrKeyMap.find(m_bigint); + if (foundKeyId != oldAndNewStrKeyMap.end()) { + m_bigint = foundKeyId->second; + } else { + Key oldkey = m_bigint; + m_bigint = newStrTable.set(factory->getStringTable().get(m_bigint)); + oldAndNewStrKeyMap.insert(std::pair(oldkey,m_bigint)); } + + foundKeyId = oldAndNewStrKeyMap.find(m_raw); + if (foundKeyId != oldAndNewStrKeyMap.end()) { + m_raw = foundKeyId->second; + } else { + Key oldkey = m_raw; + m_raw = newStrTable.set(factory->getStringTable().get(m_raw)); + oldAndNewStrKeyMap.insert(std::pair(oldkey,m_raw)); } + + } + + NodeHashType BigIntLiteral::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::BigIntLiteral", strlen("expression::BigIntLiteral")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void BigIntLiteral::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + if (withVirtualBase) + Positioned::save(binIo,false); + + Literal::save(binIo,false); + + factory->getStringTable().setType(m_bigint, StrTable::strToSave); + binIo.writeUInt4(m_bigint); + + } + + void BigIntLiteral::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + if (withVirtualBase) + Positioned::load(binIo, false); + + Literal::load(binIo,false); + + m_bigint = binIo.readUInt4(); + + } + + +} + + +}}} diff --git a/lib/javascript/src/expression/BinaryExpression.cpp b/lib/javascript/src/expression/BinaryExpression.cpp index b9c4188..1aa5d7c 100644 --- a/lib/javascript/src/expression/BinaryExpression.cpp +++ b/lib/javascript/src/expression/BinaryExpression.cpp @@ -66,10 +66,10 @@ namespace expression { m_operator = _operator; } - expression::Expression* BinaryExpression::getLeft() const { - expression::Expression *_node = NULL; + base::Positioned* BinaryExpression::getLeft() const { + base::Positioned *_node = NULL; if (m_hasLeft != 0) - _node = dynamic_cast(factory->getPointer(m_hasLeft)); + _node = dynamic_cast(factory->getPointer(m_hasLeft)); if ( (_node == NULL) || factory->getIsFiltered(_node)) return NULL; @@ -131,28 +131,32 @@ namespace expression { } void BinaryExpression::setLeft(NodeId _id) { - expression::Expression *_node = NULL; + base::Positioned *_node = NULL; if (_id) { if (!factory->getExist(_id)) throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); - _node = dynamic_cast (factory->getPointer(_id)); + _node = dynamic_cast (factory->getPointer(_id)); if ( _node == NULL) { throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); } if (&(_node->getFactory()) != this->factory) throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); - if (m_hasLeft) { - removeParentEdge(m_hasLeft); + if (Common::getIsBaseClassKind(_node->getNodeKind(), ndkExpression) || _node->getNodeKind() == ndkPrivateIdentifier) { + if (m_hasLeft) { + removeParentEdge(m_hasLeft); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasLeft, m_id, edkBinaryExpression_HasLeft); + } + m_hasLeft = _node->getId(); + if (m_hasLeft != 0) + setParentEdge(factory->getPointer(m_hasLeft), edkBinaryExpression_HasLeft); if (factory->getExistsReverseEdges()) - factory->reverseEdges->removeEdge(m_hasLeft, m_id, edkBinaryExpression_HasLeft); + factory->reverseEdges->insertEdge(m_hasLeft, this->getId(), edkBinaryExpression_HasLeft); + } else { + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); } - m_hasLeft = _node->getId(); - if (m_hasLeft != 0) - setParentEdge(factory->getPointer(m_hasLeft), edkBinaryExpression_HasLeft); - if (factory->getExistsReverseEdges()) - factory->reverseEdges->insertEdge(m_hasLeft, this->getId(), edkBinaryExpression_HasLeft); } else { if (m_hasLeft) { throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); @@ -160,7 +164,7 @@ namespace expression { } } - void BinaryExpression::setLeft(expression::Expression *_node) { + void BinaryExpression::setLeft(base::Positioned *_node) { if (_node == NULL) throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); diff --git a/lib/javascript/src/expression/CallExpression.cpp b/lib/javascript/src/expression/CallExpression.cpp index a213e1e..182ad36 100644 --- a/lib/javascript/src/expression/CallExpression.cpp +++ b/lib/javascript/src/expression/CallExpression.cpp @@ -36,6 +36,7 @@ namespace expression { CallExpression::CallExpression(NodeId _id, Factory *_factory) : Positioned(_id, _factory), Expression(_id, _factory), + ChainElement(_id, _factory), m_hasCallee(0), hasArgumentsContainer(), callsContainer() @@ -64,6 +65,7 @@ namespace expression { base::Positioned::prepareDelete(false); } expression::Expression::prepareDelete(false); + expression::ChainElement::prepareDelete(false); } NodeKind CallExpression::getNodeKind() const { @@ -144,6 +146,9 @@ namespace expression { if (expression::Expression::setEdge(edgeKind, edgeEnd, false)) { return true; } + if (expression::ChainElement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } return false; } @@ -169,6 +174,9 @@ namespace expression { if (expression::Expression::removeEdge(edgeKind, edgeEnd, false)) { return true; } + if (expression::ChainElement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } return false; } @@ -324,7 +332,10 @@ namespace expression { double CallExpression::getSimilarity(const base::Base& base){ if(base.getNodeKind() == getNodeKind()) { - return 1.0; + const CallExpression& node = dynamic_cast(base); + double matchAttrs = 0; + if(node.getOptional() == getOptional()) ++matchAttrs; + return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; } else { return 0.0; } @@ -357,6 +368,8 @@ namespace expression { Expression::save(binIo,false); + ChainElement::save(binIo,false); + binIo.writeUInt4(m_hasCallee); @@ -377,6 +390,8 @@ namespace expression { Expression::load(binIo,false); + ChainElement::load(binIo,false); + m_hasCallee = binIo.readUInt4(); if (m_hasCallee != 0) setParentEdge(factory->getPointer(m_hasCallee),edkCallExpression_HasCallee); diff --git a/lib/javascript/src/expression/ChainElement.cpp b/lib/javascript/src/expression/ChainElement.cpp new file mode 100644 index 0000000..281c0d5 --- /dev/null +++ b/lib/javascript/src/expression/ChainElement.cpp @@ -0,0 +1,147 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "javascript/inc/javascript.h" +#include "javascript/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "javascript/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace javascript { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + ChainElement::ChainElement(NodeId _id, Factory *_factory) : + Positioned(_id, _factory), + m_optional(false) + { + } + + ChainElement::~ChainElement() { + } + + void ChainElement::prepareDelete(bool tryOnVirtualParent){ + if (tryOnVirtualParent) { + base::Positioned::prepareDelete(false); + } + } + + NodeKind ChainElement::getNodeKind() const { + return ndkChainElement; + } + + bool ChainElement::getOptional() const { + return m_optional; + } + + void ChainElement::setOptional(bool _optional) { + m_optional = _optional; + } + + bool ChainElement::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (tryOnVirtualParent) { + if (base::Positioned::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + } + return false; + } + + bool ChainElement::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (tryOnVirtualParent) { + if (base::Positioned::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + } + return false; + } + + void ChainElement::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void ChainElement::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double ChainElement::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const ChainElement& node = dynamic_cast(base); + double matchAttrs = 0; + if(node.getOptional() == getOptional()) ++matchAttrs; + return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void ChainElement::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType ChainElement::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::ChainElement", strlen("expression::ChainElement")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void ChainElement::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + if (withVirtualBase) + Positioned::save(binIo,false); + + unsigned char boolValues = 0; + boolValues <<= 1; + if (m_optional) + boolValues |= 1; + binIo.writeUByte1(boolValues); + + } + + void ChainElement::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + if (withVirtualBase) + Positioned::load(binIo,false); + + unsigned char boolValues = binIo.readUByte1(); + m_optional = boolValues & 1; + boolValues >>= 1; + + } + + +} + + +}}} diff --git a/lib/javascript/src/expression/ChainExpression.cpp b/lib/javascript/src/expression/ChainExpression.cpp new file mode 100644 index 0000000..5844a45 --- /dev/null +++ b/lib/javascript/src/expression/ChainExpression.cpp @@ -0,0 +1,215 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "javascript/inc/javascript.h" +#include "javascript/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "javascript/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace javascript { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + ChainExpression::ChainExpression(NodeId _id, Factory *_factory) : + Positioned(_id, _factory), + Expression(_id, _factory), + m_hasExpression(0) + { + } + + ChainExpression::~ChainExpression() { + } + + void ChainExpression::prepareDelete(bool tryOnVirtualParent){ + removeExpression(); + if (tryOnVirtualParent) { + base::Positioned::prepareDelete(false); + } + expression::Expression::prepareDelete(false); + } + + NodeKind ChainExpression::getNodeKind() const { + return ndkChainExpression; + } + + expression::ChainElement* ChainExpression::getExpression() const { + expression::ChainElement *_node = NULL; + if (m_hasExpression != 0) + _node = dynamic_cast(factory->getPointer(m_hasExpression)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool ChainExpression::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkChainExpression_HasExpression: + setExpression(edgeEnd); + return true; + default: + break; + } + if (tryOnVirtualParent) { + if (base::Positioned::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + } + if (expression::Expression::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool ChainExpression::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkChainExpression_HasExpression: + removeExpression(); + return true; + default: + break; + } + if (tryOnVirtualParent) { + if (base::Positioned::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + } + if (expression::Expression::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void ChainExpression::setExpression(NodeId _id) { + expression::ChainElement *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasExpression) { + removeParentEdge(m_hasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpression, m_id, edkChainExpression_HasExpression); + } + m_hasExpression = _node->getId(); + if (m_hasExpression != 0) + setParentEdge(factory->getPointer(m_hasExpression), edkChainExpression_HasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasExpression, this->getId(), edkChainExpression_HasExpression); + } else { + if (m_hasExpression) { + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void ChainExpression::setExpression(expression::ChainElement *_node) { + if (_node == NULL) + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setExpression(_node->getId()); + } + + void ChainExpression::removeExpression() { + if (m_hasExpression) { + removeParentEdge(m_hasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpression, m_id, edkChainExpression_HasExpression); + } + m_hasExpression = 0; + } + + void ChainExpression::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void ChainExpression::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double ChainExpression::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void ChainExpression::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType ChainExpression::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::ChainExpression", strlen("expression::ChainExpression")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void ChainExpression::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + if (withVirtualBase) + Positioned::save(binIo,false); + + Expression::save(binIo,false); + + binIo.writeUInt4(m_hasExpression); + + } + + void ChainExpression::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + if (withVirtualBase) + Positioned::load(binIo, false); + + Expression::load(binIo,false); + + m_hasExpression = binIo.readUInt4(); + if (m_hasExpression != 0) + setParentEdge(factory->getPointer(m_hasExpression),edkChainExpression_HasExpression); + + } + + +} + + +}}} diff --git a/lib/javascript/src/expression/ImportExpression.cpp b/lib/javascript/src/expression/ImportExpression.cpp new file mode 100644 index 0000000..9b57f39 --- /dev/null +++ b/lib/javascript/src/expression/ImportExpression.cpp @@ -0,0 +1,215 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "javascript/inc/javascript.h" +#include "javascript/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "javascript/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace javascript { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + ImportExpression::ImportExpression(NodeId _id, Factory *_factory) : + Positioned(_id, _factory), + Expression(_id, _factory), + m_hasSource(0) + { + } + + ImportExpression::~ImportExpression() { + } + + void ImportExpression::prepareDelete(bool tryOnVirtualParent){ + removeSource(); + if (tryOnVirtualParent) { + base::Positioned::prepareDelete(false); + } + expression::Expression::prepareDelete(false); + } + + NodeKind ImportExpression::getNodeKind() const { + return ndkImportExpression; + } + + expression::Expression* ImportExpression::getSource() const { + expression::Expression *_node = NULL; + if (m_hasSource != 0) + _node = dynamic_cast(factory->getPointer(m_hasSource)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool ImportExpression::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkImportExpression_HasSource: + setSource(edgeEnd); + return true; + default: + break; + } + if (tryOnVirtualParent) { + if (base::Positioned::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + } + if (expression::Expression::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool ImportExpression::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkImportExpression_HasSource: + removeSource(); + return true; + default: + break; + } + if (tryOnVirtualParent) { + if (base::Positioned::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + } + if (expression::Expression::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void ImportExpression::setSource(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasSource) { + removeParentEdge(m_hasSource); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasSource, m_id, edkImportExpression_HasSource); + } + m_hasSource = _node->getId(); + if (m_hasSource != 0) + setParentEdge(factory->getPointer(m_hasSource), edkImportExpression_HasSource); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasSource, this->getId(), edkImportExpression_HasSource); + } else { + if (m_hasSource) { + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void ImportExpression::setSource(expression::Expression *_node) { + if (_node == NULL) + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setSource(_node->getId()); + } + + void ImportExpression::removeSource() { + if (m_hasSource) { + removeParentEdge(m_hasSource); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasSource, m_id, edkImportExpression_HasSource); + } + m_hasSource = 0; + } + + void ImportExpression::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void ImportExpression::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double ImportExpression::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void ImportExpression::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType ImportExpression::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::ImportExpression", strlen("expression::ImportExpression")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void ImportExpression::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + if (withVirtualBase) + Positioned::save(binIo,false); + + Expression::save(binIo,false); + + binIo.writeUInt4(m_hasSource); + + } + + void ImportExpression::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + if (withVirtualBase) + Positioned::load(binIo, false); + + Expression::load(binIo,false); + + m_hasSource = binIo.readUInt4(); + if (m_hasSource != 0) + setParentEdge(factory->getPointer(m_hasSource),edkImportExpression_HasSource); + + } + + +} + + +}}} diff --git a/lib/javascript/src/expression/MemberExpression.cpp b/lib/javascript/src/expression/MemberExpression.cpp index 52af439..1226ac9 100644 --- a/lib/javascript/src/expression/MemberExpression.cpp +++ b/lib/javascript/src/expression/MemberExpression.cpp @@ -37,6 +37,7 @@ namespace expression { Positioned(_id, _factory), Expression(_id, _factory), Pattern(_id, _factory), + ChainElement(_id, _factory), m_computed(false), m_hasProperty(0), m_hasObject(0) @@ -54,6 +55,7 @@ namespace expression { } expression::Expression::prepareDelete(false); statement::Pattern::prepareDelete(false); + expression::ChainElement::prepareDelete(false); } NodeKind MemberExpression::getNodeKind() const { @@ -68,10 +70,10 @@ namespace expression { m_computed = _computed; } - expression::Expression* MemberExpression::getProperty() const { - expression::Expression *_node = NULL; + base::Positioned* MemberExpression::getProperty() const { + base::Positioned *_node = NULL; if (m_hasProperty != 0) - _node = dynamic_cast(factory->getPointer(m_hasProperty)); + _node = dynamic_cast(factory->getPointer(m_hasProperty)); if ( (_node == NULL) || factory->getIsFiltered(_node)) return NULL; @@ -110,6 +112,9 @@ namespace expression { if (statement::Pattern::setEdge(edgeKind, edgeEnd, false)) { return true; } + if (expression::ChainElement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } return false; } @@ -135,32 +140,39 @@ namespace expression { if (statement::Pattern::removeEdge(edgeKind, edgeEnd, false)) { return true; } + if (expression::ChainElement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } return false; } void MemberExpression::setProperty(NodeId _id) { - expression::Expression *_node = NULL; + base::Positioned *_node = NULL; if (_id) { if (!factory->getExist(_id)) throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); - _node = dynamic_cast (factory->getPointer(_id)); + _node = dynamic_cast (factory->getPointer(_id)); if ( _node == NULL) { throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); } if (&(_node->getFactory()) != this->factory) throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); - if (m_hasProperty) { - removeParentEdge(m_hasProperty); + if (Common::getIsBaseClassKind(_node->getNodeKind(), ndkExpression) || _node->getNodeKind() == ndkPrivateIdentifier) { + if (m_hasProperty) { + removeParentEdge(m_hasProperty); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasProperty, m_id, edkMemberExpression_HasProperty); + } + m_hasProperty = _node->getId(); + if (m_hasProperty != 0) + setParentEdge(factory->getPointer(m_hasProperty), edkMemberExpression_HasProperty); if (factory->getExistsReverseEdges()) - factory->reverseEdges->removeEdge(m_hasProperty, m_id, edkMemberExpression_HasProperty); + factory->reverseEdges->insertEdge(m_hasProperty, this->getId(), edkMemberExpression_HasProperty); + } else { + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); } - m_hasProperty = _node->getId(); - if (m_hasProperty != 0) - setParentEdge(factory->getPointer(m_hasProperty), edkMemberExpression_HasProperty); - if (factory->getExistsReverseEdges()) - factory->reverseEdges->insertEdge(m_hasProperty, this->getId(), edkMemberExpression_HasProperty); } else { if (m_hasProperty) { throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); @@ -168,7 +180,7 @@ namespace expression { } } - void MemberExpression::setProperty(expression::Expression *_node) { + void MemberExpression::setProperty(base::Positioned *_node) { if (_node == NULL) throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); @@ -246,8 +258,9 @@ namespace expression { if(base.getNodeKind() == getNodeKind()) { const MemberExpression& node = dynamic_cast(base); double matchAttrs = 0; + if(node.getOptional() == getOptional()) ++matchAttrs; if(node.getComputed() == getComputed()) ++matchAttrs; - return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + return matchAttrs / (2 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; } else { return 0.0; } @@ -282,6 +295,8 @@ namespace expression { Pattern::save(binIo,false); + ChainElement::save(binIo,false); + unsigned char boolValues = 0; boolValues <<= 1; if (m_computed) @@ -301,6 +316,8 @@ namespace expression { Pattern::load(binIo,false); + ChainElement::load(binIo,false); + unsigned char boolValues = binIo.readUByte1(); m_computed = boolValues & 1; boolValues >>= 1; diff --git a/lib/javascript/src/expression/ObjectExpression.cpp b/lib/javascript/src/expression/ObjectExpression.cpp index bd69991..e983635 100644 --- a/lib/javascript/src/expression/ObjectExpression.cpp +++ b/lib/javascript/src/expression/ObjectExpression.cpp @@ -127,7 +127,7 @@ namespace expression { if (&(_node->getFactory()) != this->factory) throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); - if (!(Common::getIsProperty(*_node) || (_node->getNodeKind() == ndkSpreadElement) )) + if (!((_node->getNodeKind() == ndkProperty) || (_node->getNodeKind() == ndkSpreadElement) )) throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); hasPropertiesContainer.push_back(_node->getId()); diff --git a/lib/javascript/src/expression/PrivateIdentifier.cpp b/lib/javascript/src/expression/PrivateIdentifier.cpp new file mode 100644 index 0000000..16dfaaf --- /dev/null +++ b/lib/javascript/src/expression/PrivateIdentifier.cpp @@ -0,0 +1,157 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "javascript/inc/javascript.h" +#include "javascript/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "javascript/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace javascript { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + PrivateIdentifier::PrivateIdentifier(NodeId _id, Factory *_factory) : + Positioned(_id, _factory), + Named(_id, _factory) + { + } + + PrivateIdentifier::~PrivateIdentifier() { + } + + void PrivateIdentifier::prepareDelete(bool tryOnVirtualParent){ + if (tryOnVirtualParent) { + base::Positioned::prepareDelete(false); + } + base::Named::prepareDelete(false); + } + + NodeKind PrivateIdentifier::getNodeKind() const { + return ndkPrivateIdentifier; + } + + bool PrivateIdentifier::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (tryOnVirtualParent) { + if (base::Positioned::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + } + if (base::Named::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool PrivateIdentifier::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (tryOnVirtualParent) { + if (base::Positioned::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + } + if (base::Named::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void PrivateIdentifier::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void PrivateIdentifier::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double PrivateIdentifier::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const PrivateIdentifier& node = dynamic_cast(base); + double matchAttrs = 0; + std::string str1, str2; + size_t strMax; + double strSim; + str1 = getName(); + str2 = node.getName(); + strMax = std::max(str1.size(), str2.size()); + strSim = 1 - ((double)common::math::editDistance(str1, str2) / (strMax > 0 ? strMax : 1)); + if (strSim < Common::SimilarityMinForStrings) + return 0.0; + matchAttrs += strSim; + return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void PrivateIdentifier::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + foundKeyId = oldAndNewStrKeyMap.find(m_name); + if (foundKeyId != oldAndNewStrKeyMap.end()) { + m_name = foundKeyId->second; + } else { + Key oldkey = m_name; + m_name = newStrTable.set(factory->getStringTable().get(m_name)); + oldAndNewStrKeyMap.insert(std::pair(oldkey,m_name)); } + + } + + NodeHashType PrivateIdentifier::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::PrivateIdentifier", strlen("expression::PrivateIdentifier")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void PrivateIdentifier::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + if (withVirtualBase) + Positioned::save(binIo,false); + + Named::save(binIo,false); + + } + + void PrivateIdentifier::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + if (withVirtualBase) + Positioned::load(binIo,false); + + Named::load(binIo,false); + + } + + +} + + +}}} diff --git a/lib/javascript/src/statement/ForOfStatement.cpp b/lib/javascript/src/statement/ForOfStatement.cpp index d31bf01..c1b44d3 100644 --- a/lib/javascript/src/statement/ForOfStatement.cpp +++ b/lib/javascript/src/statement/ForOfStatement.cpp @@ -36,7 +36,7 @@ namespace statement { ForOfStatement::ForOfStatement(NodeId _id, Factory *_factory) : Positioned(_id, _factory), ForInStatement(_id, _factory), - m_async(false) + m_await(false) { } @@ -54,12 +54,12 @@ namespace statement { return ndkForOfStatement; } - bool ForOfStatement::getAsync() const { - return m_async; + bool ForOfStatement::getAwait() const { + return m_await; } - void ForOfStatement::setAsync(bool _async) { - m_async = _async; + void ForOfStatement::setAwait(bool _await) { + m_await = _await; } bool ForOfStatement::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { @@ -98,7 +98,7 @@ namespace statement { if(base.getNodeKind() == getNodeKind()) { const ForOfStatement& node = dynamic_cast(base); double matchAttrs = 0; - if(node.getAsync() == getAsync()) ++matchAttrs; + if(node.getAwait() == getAwait()) ++matchAttrs; return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; } else { return 0.0; @@ -134,7 +134,7 @@ namespace statement { unsigned char boolValues = 0; boolValues <<= 1; - if (m_async) + if (m_await) boolValues |= 1; binIo.writeUByte1(boolValues); @@ -147,7 +147,7 @@ namespace statement { ForInStatement::load(binIo,false); unsigned char boolValues = binIo.readUByte1(); - m_async = boolValues & 1; + m_await = boolValues & 1; boolValues >>= 1; } diff --git a/lib/javascript/src/statement/ObjectPattern.cpp b/lib/javascript/src/statement/ObjectPattern.cpp index be85dac..20fc4c5 100644 --- a/lib/javascript/src/statement/ObjectPattern.cpp +++ b/lib/javascript/src/statement/ObjectPattern.cpp @@ -127,7 +127,7 @@ namespace statement { if (&(_node->getFactory()) != this->factory) throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); - if (!(Common::getIsProperty(*_node) || (_node->getNodeKind() == ndkRestElement) )) + if (!((_node->getNodeKind() == ndkProperty) || (_node->getNodeKind() == ndkRestElement) )) throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); hasPropertiesContainer.push_back(_node->getId()); diff --git a/lib/javascript/src/structure/ClassBody.cpp b/lib/javascript/src/structure/ClassBody.cpp index 821d6df..c602b2c 100644 --- a/lib/javascript/src/structure/ClassBody.cpp +++ b/lib/javascript/src/structure/ClassBody.cpp @@ -57,12 +57,12 @@ namespace structure { return ndkClassBody; } - ListIterator ClassBody::getBodyListIteratorBegin() const { - return ListIterator(&hasBodyContainer, factory, true); + ListIterator ClassBody::getBodyListIteratorBegin() const { + return ListIterator(&hasBodyContainer, factory, true); } - ListIterator ClassBody::getBodyListIteratorEnd() const { - return ListIterator(&hasBodyContainer, factory, false); + ListIterator ClassBody::getBodyListIteratorEnd() const { + return ListIterator(&hasBodyContainer, factory, false); } bool ClassBody::getBodyIsEmpty() const { @@ -71,8 +71,8 @@ namespace structure { unsigned int ClassBody::getBodySize() const { unsigned int size = 0; - ListIterator endIt = getBodyListIteratorEnd(); - for (ListIterator it = getBodyListIteratorBegin(); it != endIt; ++it) { + ListIterator endIt = getBodyListIteratorEnd(); + for (ListIterator it = getBodyListIteratorBegin(); it != endIt; ++it) { ++size; } return size; @@ -106,14 +106,14 @@ namespace structure { return false; } - void ClassBody::addBody(const structure::MethodDefinition *_node) { + void ClassBody::addBody(const base::Positioned *_node) { if (_node == NULL) throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); if (&(_node->getFactory()) != this->factory) throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); - if (!((_node->getNodeKind() == ndkMethodDefinition) )) + if (!((_node->getNodeKind() == ndkMethodDefinition) || (_node->getNodeKind() == ndkPropertyDefinition) )) throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); hasBodyContainer.push_back(_node->getId()); @@ -124,7 +124,7 @@ namespace structure { } void ClassBody::addBody(NodeId _id) { - const structure::MethodDefinition *node = dynamic_cast(factory->getPointer(_id)); + const base::Positioned *node = dynamic_cast(factory->getPointer(_id)); if (node == NULL) throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); addBody( node ); @@ -134,7 +134,7 @@ namespace structure { if (!factory->getExist(id)) throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); - ListIterator::Container::iterator it = find(hasBodyContainer.begin(), hasBodyContainer.end(), id); + ListIterator::Container::iterator it = find(hasBodyContainer.begin(), hasBodyContainer.end(), id); if (it == hasBodyContainer.end()) throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); @@ -147,7 +147,7 @@ namespace structure { factory->reverseEdges->removeEdge(id, this->getId(), edkClassBody_HasBody); } - void ClassBody::removeBody(structure::MethodDefinition *_node) { + void ClassBody::removeBody(base::Positioned *_node) { if (_node == NULL) throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); @@ -195,7 +195,7 @@ namespace structure { Positioned::save(binIo,false); - for (ListIterator::Container::const_iterator it = hasBodyContainer.begin(); it != hasBodyContainer.end(); ++it) { + for (ListIterator::Container::const_iterator it = hasBodyContainer.begin(); it != hasBodyContainer.end(); ++it) { binIo.writeUInt4(*it); } binIo.writeUInt4(0); // This is the end sign diff --git a/lib/javascript/src/structure/MethodDefinition.cpp b/lib/javascript/src/structure/MethodDefinition.cpp index c42557d..f699624 100644 --- a/lib/javascript/src/structure/MethodDefinition.cpp +++ b/lib/javascript/src/structure/MethodDefinition.cpp @@ -80,10 +80,10 @@ namespace structure { m_static = _static; } - expression::Expression* MethodDefinition::getKey() const { - expression::Expression *_node = NULL; + base::Positioned* MethodDefinition::getKey() const { + base::Positioned *_node = NULL; if (m_hasKey != 0) - _node = dynamic_cast(factory->getPointer(m_hasKey)); + _node = dynamic_cast(factory->getPointer(m_hasKey)); if ( (_node == NULL) || factory->getIsFiltered(_node)) return NULL; @@ -135,28 +135,32 @@ namespace structure { } void MethodDefinition::setKey(NodeId _id) { - expression::Expression *_node = NULL; + base::Positioned *_node = NULL; if (_id) { if (!factory->getExist(_id)) throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); - _node = dynamic_cast (factory->getPointer(_id)); + _node = dynamic_cast (factory->getPointer(_id)); if ( _node == NULL) { throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); } if (&(_node->getFactory()) != this->factory) throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); - if (m_hasKey) { - removeParentEdge(m_hasKey); + if (Common::getIsBaseClassKind(_node->getNodeKind(), ndkExpression) || _node->getNodeKind() == ndkPrivateIdentifier) { + if (m_hasKey) { + removeParentEdge(m_hasKey); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasKey, m_id, edkMethodDefinition_HasKey); + } + m_hasKey = _node->getId(); + if (m_hasKey != 0) + setParentEdge(factory->getPointer(m_hasKey), edkMethodDefinition_HasKey); if (factory->getExistsReverseEdges()) - factory->reverseEdges->removeEdge(m_hasKey, m_id, edkMethodDefinition_HasKey); + factory->reverseEdges->insertEdge(m_hasKey, this->getId(), edkMethodDefinition_HasKey); + } else { + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); } - m_hasKey = _node->getId(); - if (m_hasKey != 0) - setParentEdge(factory->getPointer(m_hasKey), edkMethodDefinition_HasKey); - if (factory->getExistsReverseEdges()) - factory->reverseEdges->insertEdge(m_hasKey, this->getId(), edkMethodDefinition_HasKey); } else { if (m_hasKey) { throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); @@ -164,7 +168,7 @@ namespace structure { } } - void MethodDefinition::setKey(expression::Expression *_node) { + void MethodDefinition::setKey(base::Positioned *_node) { if (_node == NULL) throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); diff --git a/lib/javascript/src/structure/PropertyDefinition.cpp b/lib/javascript/src/structure/PropertyDefinition.cpp new file mode 100644 index 0000000..358f064 --- /dev/null +++ b/lib/javascript/src/structure/PropertyDefinition.cpp @@ -0,0 +1,305 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "javascript/inc/javascript.h" +#include "javascript/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "javascript/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace javascript { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace structure { + PropertyDefinition::PropertyDefinition(NodeId _id, Factory *_factory) : + Positioned(_id, _factory), + m_computed(false), + m_static(false), + m_hasKey(0), + m_hasValue(0) + { + } + + PropertyDefinition::~PropertyDefinition() { + } + + void PropertyDefinition::prepareDelete(bool tryOnVirtualParent){ + removeKey(); + removeValue(); + base::Positioned::prepareDelete(false); + } + + NodeKind PropertyDefinition::getNodeKind() const { + return ndkPropertyDefinition; + } + + bool PropertyDefinition::getComputed() const { + return m_computed; + } + + bool PropertyDefinition::getStatic() const { + return m_static; + } + + void PropertyDefinition::setComputed(bool _computed) { + m_computed = _computed; + } + + void PropertyDefinition::setStatic(bool _static) { + m_static = _static; + } + + base::Positioned* PropertyDefinition::getKey() const { + base::Positioned *_node = NULL; + if (m_hasKey != 0) + _node = dynamic_cast(factory->getPointer(m_hasKey)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + expression::Expression* PropertyDefinition::getValue() const { + expression::Expression *_node = NULL; + if (m_hasValue != 0) + _node = dynamic_cast(factory->getPointer(m_hasValue)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool PropertyDefinition::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkPropertyDefinition_HasKey: + setKey(edgeEnd); + return true; + case edkPropertyDefinition_HasValue: + setValue(edgeEnd); + return true; + default: + break; + } + if (base::Positioned::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool PropertyDefinition::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkPropertyDefinition_HasKey: + removeKey(); + return true; + case edkPropertyDefinition_HasValue: + removeValue(); + return true; + default: + break; + } + if (base::Positioned::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void PropertyDefinition::setKey(NodeId _id) { + base::Positioned *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (_node->getNodeKind() == ndkPrivateIdentifier || Common::getIsBaseClassKind(_node->getNodeKind(), ndkExpression)) { + if (m_hasKey) { + removeParentEdge(m_hasKey); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasKey, m_id, edkPropertyDefinition_HasKey); + } + m_hasKey = _node->getId(); + if (m_hasKey != 0) + setParentEdge(factory->getPointer(m_hasKey), edkPropertyDefinition_HasKey); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasKey, this->getId(), edkPropertyDefinition_HasKey); + } else { + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + } else { + if (m_hasKey) { + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void PropertyDefinition::setKey(base::Positioned *_node) { + if (_node == NULL) + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setKey(_node->getId()); + } + + void PropertyDefinition::removeKey() { + if (m_hasKey) { + removeParentEdge(m_hasKey); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasKey, m_id, edkPropertyDefinition_HasKey); + } + m_hasKey = 0; + } + + void PropertyDefinition::setValue(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasValue) { + removeParentEdge(m_hasValue); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasValue, m_id, edkPropertyDefinition_HasValue); + } + m_hasValue = _node->getId(); + if (m_hasValue != 0) + setParentEdge(factory->getPointer(m_hasValue), edkPropertyDefinition_HasValue); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasValue, this->getId(), edkPropertyDefinition_HasValue); + } else { + if (m_hasValue) { + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void PropertyDefinition::setValue(expression::Expression *_node) { + if (_node == NULL) + throw JavascriptException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setValue(_node->getId()); + } + + void PropertyDefinition::removeValue() { + if (m_hasValue) { + removeParentEdge(m_hasValue); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasValue, m_id, edkPropertyDefinition_HasValue); + } + m_hasValue = 0; + } + + void PropertyDefinition::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void PropertyDefinition::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double PropertyDefinition::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const PropertyDefinition& node = dynamic_cast(base); + double matchAttrs = 0; + if(node.getComputed() == getComputed()) ++matchAttrs; + if(node.getStatic() == getStatic()) ++matchAttrs; + return matchAttrs / (2 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void PropertyDefinition::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType PropertyDefinition::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "structure::PropertyDefinition", strlen("structure::PropertyDefinition")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void PropertyDefinition::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Positioned::save(binIo,false); + + unsigned char boolValues = 0; + boolValues <<= 1; + if (m_computed) + boolValues |= 1; + boolValues <<= 1; + if (m_static) + boolValues |= 1; + binIo.writeUByte1(boolValues); + + binIo.writeUInt4(m_hasKey); + binIo.writeUInt4(m_hasValue); + + } + + void PropertyDefinition::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Positioned::load(binIo,false); + + unsigned char boolValues = binIo.readUByte1(); + m_static = boolValues & 1; + boolValues >>= 1; + m_computed = boolValues & 1; + boolValues >>= 1; + + m_hasKey = binIo.readUInt4(); + if (m_hasKey != 0) + setParentEdge(factory->getPointer(m_hasKey),edkPropertyDefinition_HasKey); + + m_hasValue = binIo.readUInt4(); + if (m_hasValue != 0) + setParentEdge(factory->getPointer(m_hasValue),edkPropertyDefinition_HasValue); + + } + + +} + + +}}} diff --git a/lib/javascript/src/visitors/Visitor.cpp b/lib/javascript/src/visitors/Visitor.cpp index e39bf79..eae200b 100644 --- a/lib/javascript/src/visitors/Visitor.cpp +++ b/lib/javascript/src/visitors/Visitor.cpp @@ -106,14 +106,14 @@ void Visitor::visit(const expression::AssignmentExpression& node , bool callVirt void Visitor::visitEnd(const expression::AssignmentExpression& node , bool callVirtualBase) { } -void Visitor::visit(const expression::AssignmentProperty& node , bool callVirtualBase) {} - -void Visitor::visitEnd(const expression::AssignmentProperty& node , bool callVirtualBase) { } - void Visitor::visit(const expression::AwaitExpression& node , bool callVirtualBase) {} void Visitor::visitEnd(const expression::AwaitExpression& node , bool callVirtualBase) { } +void Visitor::visit(const expression::BigIntLiteral& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::BigIntLiteral& node , bool callVirtualBase) { } + void Visitor::visit(const expression::BinaryExpression& node , bool callVirtualBase) {} void Visitor::visitEnd(const expression::BinaryExpression& node , bool callVirtualBase) { } @@ -126,6 +126,14 @@ void Visitor::visit(const expression::CallExpression& node , bool callVirtualBas void Visitor::visitEnd(const expression::CallExpression& node , bool callVirtualBase) { } +void Visitor::visit(const expression::ChainElement& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::ChainElement& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::ChainExpression& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::ChainExpression& node , bool callVirtualBase) { } + void Visitor::visit(const expression::ClassExpression& node , bool callVirtualBase) {} void Visitor::visitEnd(const expression::ClassExpression& node , bool callVirtualBase) { } @@ -142,6 +150,10 @@ void Visitor::visit(const expression::Identifier& node , bool callVirtualBase) { void Visitor::visitEnd(const expression::Identifier& node , bool callVirtualBase) { } +void Visitor::visit(const expression::ImportExpression& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::ImportExpression& node , bool callVirtualBase) { } + void Visitor::visit(const expression::LogicalExpression& node , bool callVirtualBase) {} void Visitor::visitEnd(const expression::LogicalExpression& node , bool callVirtualBase) { } @@ -170,6 +182,10 @@ void Visitor::visit(const expression::ObjectExpression& node , bool callVirtualB void Visitor::visitEnd(const expression::ObjectExpression& node , bool callVirtualBase) { } +void Visitor::visit(const expression::PrivateIdentifier& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::PrivateIdentifier& node , bool callVirtualBase) { } + void Visitor::visit(const expression::Property& node , bool callVirtualBase) {} void Visitor::visitEnd(const expression::Property& node , bool callVirtualBase) { } @@ -346,6 +362,10 @@ void Visitor::visit(const structure::MethodDefinition& node , bool callVirtualBa void Visitor::visitEnd(const structure::MethodDefinition& node , bool callVirtualBase) { } +void Visitor::visit(const structure::PropertyDefinition& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const structure::PropertyDefinition& node , bool callVirtualBase) { } + void Visitor::visitPositioned_Comments(const base::Positioned& begin, const base::Comment& end) { } void Visitor::visitEndPositioned_Comments(const base::Positioned& begin, const base::Comment& end) { } @@ -362,6 +382,10 @@ void Visitor::visitExportAllDeclaration_HasSource(const declaration::ExportAllDe void Visitor::visitEndExportAllDeclaration_HasSource(const declaration::ExportAllDeclaration& begin, const expression::Literal& end) { } +void Visitor::visitExportAllDeclaration_HasExported(const declaration::ExportAllDeclaration& begin, const expression::Identifier& end) { } + +void Visitor::visitEndExportAllDeclaration_HasExported(const declaration::ExportAllDeclaration& begin, const expression::Identifier& end) { } + void Visitor::visitExportDefaultDeclaration_HasDeclaration(const declaration::ExportDefaultDeclaration& begin, const base::Positioned& end) { } void Visitor::visitEndExportDefaultDeclaration_HasDeclaration(const declaration::ExportDefaultDeclaration& begin, const base::Positioned& end) { } @@ -414,9 +438,9 @@ void Visitor::visitAwaitExpression_HasArgument(const expression::AwaitExpression void Visitor::visitEndAwaitExpression_HasArgument(const expression::AwaitExpression& begin, const expression::Expression& end) { } -void Visitor::visitBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const expression::Expression& end) { } +void Visitor::visitBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const base::Positioned& end) { } -void Visitor::visitEndBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const expression::Expression& end) { } +void Visitor::visitEndBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const base::Positioned& end) { } void Visitor::visitBinaryExpression_HasRight(const expression::BinaryExpression& begin, const expression::Expression& end) { } @@ -434,6 +458,10 @@ void Visitor::visitCallExpression_Calls(const expression::CallExpression& begin, void Visitor::visitEndCallExpression_Calls(const expression::CallExpression& begin, const statement::Function& end) { } +void Visitor::visitChainExpression_HasExpression(const expression::ChainExpression& begin, const expression::ChainElement& end) { } + +void Visitor::visitEndChainExpression_HasExpression(const expression::ChainExpression& begin, const expression::ChainElement& end) { } + void Visitor::visitConditionalExpression_HasAlternate(const expression::ConditionalExpression& begin, const expression::Expression& end) { } void Visitor::visitEndConditionalExpression_HasAlternate(const expression::ConditionalExpression& begin, const expression::Expression& end) { } @@ -450,6 +478,10 @@ void Visitor::visitIdentifier_RefersTo(const expression::Identifier& begin, cons void Visitor::visitEndIdentifier_RefersTo(const expression::Identifier& begin, const base::Positioned& end) { } +void Visitor::visitImportExpression_HasSource(const expression::ImportExpression& begin, const expression::Expression& end) { } + +void Visitor::visitEndImportExpression_HasSource(const expression::ImportExpression& begin, const expression::Expression& end) { } + void Visitor::visitLogicalExpression_HasLeft(const expression::LogicalExpression& begin, const expression::Expression& end) { } void Visitor::visitEndLogicalExpression_HasLeft(const expression::LogicalExpression& begin, const expression::Expression& end) { } @@ -458,9 +490,9 @@ void Visitor::visitLogicalExpression_HasRight(const expression::LogicalExpressio void Visitor::visitEndLogicalExpression_HasRight(const expression::LogicalExpression& begin, const expression::Expression& end) { } -void Visitor::visitMemberExpression_HasProperty(const expression::MemberExpression& begin, const expression::Expression& end) { } +void Visitor::visitMemberExpression_HasProperty(const expression::MemberExpression& begin, const base::Positioned& end) { } -void Visitor::visitEndMemberExpression_HasProperty(const expression::MemberExpression& begin, const expression::Expression& end) { } +void Visitor::visitEndMemberExpression_HasProperty(const expression::MemberExpression& begin, const base::Positioned& end) { } void Visitor::visitMemberExpression_HasObject(const expression::MemberExpression& begin, const base::Positioned& end) { } @@ -702,9 +734,9 @@ void Visitor::visitClass_HasIdentifier(const structure::Class& begin, const expr void Visitor::visitEndClass_HasIdentifier(const structure::Class& begin, const expression::Identifier& end) { } -void Visitor::visitClassBody_HasBody(const structure::ClassBody& begin, const structure::MethodDefinition& end) { } +void Visitor::visitClassBody_HasBody(const structure::ClassBody& begin, const base::Positioned& end) { } -void Visitor::visitEndClassBody_HasBody(const structure::ClassBody& begin, const structure::MethodDefinition& end) { } +void Visitor::visitEndClassBody_HasBody(const structure::ClassBody& begin, const base::Positioned& end) { } void Visitor::visitExportSpecifier_HasExported(const structure::ExportSpecifier& begin, const expression::Identifier& end) { } @@ -714,9 +746,9 @@ void Visitor::visitImportSpecifier_HasImported(const structure::ImportSpecifier& void Visitor::visitEndImportSpecifier_HasImported(const structure::ImportSpecifier& begin, const expression::Identifier& end) { } -void Visitor::visitMethodDefinition_HasKey(const structure::MethodDefinition& begin, const expression::Expression& end) { } +void Visitor::visitMethodDefinition_HasKey(const structure::MethodDefinition& begin, const base::Positioned& end) { } -void Visitor::visitEndMethodDefinition_HasKey(const structure::MethodDefinition& begin, const expression::Expression& end) { } +void Visitor::visitEndMethodDefinition_HasKey(const structure::MethodDefinition& begin, const base::Positioned& end) { } void Visitor::visitMethodDefinition_HasValue(const structure::MethodDefinition& begin, const expression::FunctionExpression& end) { } @@ -726,5 +758,13 @@ void Visitor::visitModuleSpecifier_HasLocal(const structure::ModuleSpecifier& be void Visitor::visitEndModuleSpecifier_HasLocal(const structure::ModuleSpecifier& begin, const expression::Identifier& end) { } +void Visitor::visitPropertyDefinition_HasKey(const structure::PropertyDefinition& begin, const base::Positioned& end) { } + +void Visitor::visitEndPropertyDefinition_HasKey(const structure::PropertyDefinition& begin, const base::Positioned& end) { } + +void Visitor::visitPropertyDefinition_HasValue(const structure::PropertyDefinition& begin, const expression::Expression& end) { } + +void Visitor::visitEndPropertyDefinition_HasValue(const structure::PropertyDefinition& begin, const expression::Expression& end) { } + }}} diff --git a/lib/javascript/src/visitors/VisitorAbstractNodes.cpp b/lib/javascript/src/visitors/VisitorAbstractNodes.cpp index 44106f9..797599b 100644 --- a/lib/javascript/src/visitors/VisitorAbstractNodes.cpp +++ b/lib/javascript/src/visitors/VisitorAbstractNodes.cpp @@ -219,14 +219,6 @@ void VisitorAbstractNodes::visitEnd(const expression::AssignmentExpression& node visitEnd ((base::Positioned&)node,false); } -void VisitorAbstractNodes::visit(const expression::AssignmentProperty& node , bool callVirtualBase) { - visit ((expression::Property&)node,false); -} - -void VisitorAbstractNodes::visitEnd(const expression::AssignmentProperty& node , bool callVirtualBase) { - visitEnd ((expression::Property&)node,false); -} - void VisitorAbstractNodes::visit(const expression::AwaitExpression& node , bool callVirtualBase) { if (callVirtualBase) visit ((base::Positioned&)node,false); @@ -239,6 +231,18 @@ void VisitorAbstractNodes::visitEnd(const expression::AwaitExpression& node , bo visitEnd ((base::Positioned&)node,false); } +void VisitorAbstractNodes::visit(const expression::BigIntLiteral& node , bool callVirtualBase) { + if (callVirtualBase) + visit ((base::Positioned&)node,false); + visit ((expression::Literal&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::BigIntLiteral& node , bool callVirtualBase) { + visitEnd ((expression::Literal&)node,false); + if (callVirtualBase) + visitEnd ((base::Positioned&)node,false); +} + void VisitorAbstractNodes::visit(const expression::BinaryExpression& node , bool callVirtualBase) { if (callVirtualBase) visit ((base::Positioned&)node,false); @@ -267,9 +271,33 @@ void VisitorAbstractNodes::visit(const expression::CallExpression& node , bool c if (callVirtualBase) visit ((base::Positioned&)node,false); visit ((expression::Expression&)node,false); + visit ((expression::ChainElement&)node,false); } void VisitorAbstractNodes::visitEnd(const expression::CallExpression& node , bool callVirtualBase) { + visitEnd ((expression::Expression&)node,false); + visitEnd ((expression::ChainElement&)node,false); + if (callVirtualBase) + visitEnd ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::ChainElement& node , bool callVirtualBase) { + if (callVirtualBase) + visit((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::ChainElement& node , bool callVirtualBase) { + if (callVirtualBase) + visitEnd((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::ChainExpression& node , bool callVirtualBase) { + if (callVirtualBase) + visit ((base::Positioned&)node,false); + visit ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::ChainExpression& node , bool callVirtualBase) { visitEnd ((expression::Expression&)node,false); if (callVirtualBase) visitEnd ((base::Positioned&)node,false); @@ -341,6 +369,18 @@ void VisitorAbstractNodes::visitEnd(const expression::Identifier& node , bool ca visitEnd ((base::Positioned&)node,false); } +void VisitorAbstractNodes::visit(const expression::ImportExpression& node , bool callVirtualBase) { + if (callVirtualBase) + visit ((base::Positioned&)node,false); + visit ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::ImportExpression& node , bool callVirtualBase) { + visitEnd ((expression::Expression&)node,false); + if (callVirtualBase) + visitEnd ((base::Positioned&)node,false); +} + void VisitorAbstractNodes::visit(const expression::Literal& node , bool callVirtualBase) { if (callVirtualBase) visit((base::Positioned&)node,false); @@ -370,11 +410,13 @@ void VisitorAbstractNodes::visit(const expression::MemberExpression& node , bool visit ((base::Positioned&)node,false); visit ((expression::Expression&)node,false); visit ((statement::Pattern&)node,false); + visit ((expression::ChainElement&)node,false); } void VisitorAbstractNodes::visitEnd(const expression::MemberExpression& node , bool callVirtualBase) { visitEnd ((expression::Expression&)node,false); visitEnd ((statement::Pattern&)node,false); + visitEnd ((expression::ChainElement&)node,false); if (callVirtualBase) visitEnd ((base::Positioned&)node,false); } @@ -439,6 +481,18 @@ void VisitorAbstractNodes::visitEnd(const expression::ObjectExpression& node , b visitEnd ((base::Positioned&)node,false); } +void VisitorAbstractNodes::visit(const expression::PrivateIdentifier& node , bool callVirtualBase) { + if (callVirtualBase) + visit((base::Positioned&)node,false); + visit ((base::Named&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::PrivateIdentifier& node , bool callVirtualBase) { + if (callVirtualBase) + visitEnd((base::Positioned&)node,false); + visitEnd ((base::Named&)node,false); +} + void VisitorAbstractNodes::visit(const expression::Property& node , bool callVirtualBase) { visit ((base::Positioned&)node,false); } @@ -963,5 +1017,13 @@ void VisitorAbstractNodes::visitEnd(const structure::ModuleSpecifier& node , boo visitEnd ((base::Positioned&)node,false); } +void VisitorAbstractNodes::visit(const structure::PropertyDefinition& node , bool callVirtualBase) { + visit ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const structure::PropertyDefinition& node , bool callVirtualBase) { + visitEnd ((base::Positioned&)node,false); +} + }}} diff --git a/lib/javascript/src/visitors/VisitorAsgStat.cpp b/lib/javascript/src/visitors/VisitorAsgStat.cpp index 88ed388..e2abef1 100644 --- a/lib/javascript/src/visitors/VisitorAsgStat.cpp +++ b/lib/javascript/src/visitors/VisitorAsgStat.cpp @@ -42,16 +42,19 @@ const char* VisitorAsgStat::nodeNames[] = { "expression::ArrayExpression", "expression::ArrowFunctionExpression", "expression::AssignmentExpression", - "expression::AssignmentProperty", "expression::AwaitExpression", + "expression::BigIntLiteral", "expression::BinaryExpression", "expression::BooleanLiteral", "expression::CallExpression", + "expression::ChainElement", + "expression::ChainExpression", "expression::ClassExpression", "expression::ConditionalExpression", "expression::Expression", "expression::FunctionExpression", "expression::Identifier", + "expression::ImportExpression", "expression::Literal", "expression::LogicalExpression", "expression::MemberExpression", @@ -60,6 +63,7 @@ const char* VisitorAsgStat::nodeNames[] = { "expression::NullLiteral", "expression::NumberLiteral", "expression::ObjectExpression", + "expression::PrivateIdentifier", "expression::Property", "expression::RegExpLiteral", "expression::SequenceExpression", @@ -109,6 +113,7 @@ const char* VisitorAsgStat::nodeNames[] = { "structure::ImportSpecifier", "structure::MethodDefinition", "structure::ModuleSpecifier", + "structure::PropertyDefinition", }; const unsigned short VisitorAsgStat::nodeSizes[] = { @@ -131,16 +136,19 @@ const unsigned short VisitorAsgStat::nodeSizes[] = { sizeof(expression::ArrayExpression), sizeof(expression::ArrowFunctionExpression), sizeof(expression::AssignmentExpression), - sizeof(expression::AssignmentProperty), sizeof(expression::AwaitExpression), + sizeof(expression::BigIntLiteral), sizeof(expression::BinaryExpression), sizeof(expression::BooleanLiteral), sizeof(expression::CallExpression), + sizeof(expression::ChainElement), + sizeof(expression::ChainExpression), sizeof(expression::ClassExpression), sizeof(expression::ConditionalExpression), sizeof(expression::Expression), sizeof(expression::FunctionExpression), sizeof(expression::Identifier), + sizeof(expression::ImportExpression), sizeof(expression::Literal), sizeof(expression::LogicalExpression), sizeof(expression::MemberExpression), @@ -149,6 +157,7 @@ const unsigned short VisitorAsgStat::nodeSizes[] = { sizeof(expression::NullLiteral), sizeof(expression::NumberLiteral), sizeof(expression::ObjectExpression), + sizeof(expression::PrivateIdentifier), sizeof(expression::Property), sizeof(expression::RegExpLiteral), sizeof(expression::SequenceExpression), @@ -198,16 +207,17 @@ const unsigned short VisitorAsgStat::nodeSizes[] = { sizeof(structure::ImportSpecifier), sizeof(structure::MethodDefinition), sizeof(structure::ModuleSpecifier), + sizeof(structure::PropertyDefinition), }; VisitorAsgStat::VisitorAsgStat() : VisitorAbstractNodes() { - for (int i = 0; i < 86; ++i) + for (int i = 0; i < 91; ++i) nodeStatSimple[i] = 0; - for (int i = 0; i < 86; ++i) + for (int i = 0; i < 91; ++i) nodeStatParent[i] = 0; - for (int i = 0; i < 95; ++i) + for (int i = 0; i < 100; ++i) edgeStat[i] = 0; } @@ -367,14 +377,6 @@ const unsigned short VisitorAsgStat::nodeSizes[] = { ++nodeStatSimple[ndkAssignmentExpression]; } - void VisitorAsgStat::visit(const expression::AssignmentProperty& node,bool callVirtualBase ) { - VisitorAbstractNodes::visit(node,callVirtualBase); - - ++nodeStatParent[ndkAssignmentProperty]; - if (node.getNodeKind() == ndkAssignmentProperty) - ++nodeStatSimple[ndkAssignmentProperty]; - } - void VisitorAsgStat::visit(const expression::AwaitExpression& node,bool callVirtualBase ) { VisitorAbstractNodes::visit(node,callVirtualBase); @@ -383,6 +385,14 @@ const unsigned short VisitorAsgStat::nodeSizes[] = { ++nodeStatSimple[ndkAwaitExpression]; } + void VisitorAsgStat::visit(const expression::BigIntLiteral& node,bool callVirtualBase ) { + VisitorAbstractNodes::visit(node,callVirtualBase); + + ++nodeStatParent[ndkBigIntLiteral]; + if (node.getNodeKind() == ndkBigIntLiteral) + ++nodeStatSimple[ndkBigIntLiteral]; + } + void VisitorAsgStat::visit(const expression::BinaryExpression& node,bool callVirtualBase ) { VisitorAbstractNodes::visit(node,callVirtualBase); @@ -407,6 +417,22 @@ const unsigned short VisitorAsgStat::nodeSizes[] = { ++nodeStatSimple[ndkCallExpression]; } + void VisitorAsgStat::visit(const expression::ChainElement& node,bool callVirtualBase ) { + VisitorAbstractNodes::visit(node,callVirtualBase); + + ++nodeStatParent[ndkChainElement]; + if (node.getNodeKind() == ndkChainElement) + ++nodeStatSimple[ndkChainElement]; + } + + void VisitorAsgStat::visit(const expression::ChainExpression& node,bool callVirtualBase ) { + VisitorAbstractNodes::visit(node,callVirtualBase); + + ++nodeStatParent[ndkChainExpression]; + if (node.getNodeKind() == ndkChainExpression) + ++nodeStatSimple[ndkChainExpression]; + } + void VisitorAsgStat::visit(const expression::ClassExpression& node,bool callVirtualBase ) { VisitorAbstractNodes::visit(node,callVirtualBase); @@ -447,6 +473,14 @@ const unsigned short VisitorAsgStat::nodeSizes[] = { ++nodeStatSimple[ndkIdentifier]; } + void VisitorAsgStat::visit(const expression::ImportExpression& node,bool callVirtualBase ) { + VisitorAbstractNodes::visit(node,callVirtualBase); + + ++nodeStatParent[ndkImportExpression]; + if (node.getNodeKind() == ndkImportExpression) + ++nodeStatSimple[ndkImportExpression]; + } + void VisitorAsgStat::visit(const expression::Literal& node,bool callVirtualBase ) { VisitorAbstractNodes::visit(node,callVirtualBase); @@ -511,6 +545,14 @@ const unsigned short VisitorAsgStat::nodeSizes[] = { ++nodeStatSimple[ndkObjectExpression]; } + void VisitorAsgStat::visit(const expression::PrivateIdentifier& node,bool callVirtualBase ) { + VisitorAbstractNodes::visit(node,callVirtualBase); + + ++nodeStatParent[ndkPrivateIdentifier]; + if (node.getNodeKind() == ndkPrivateIdentifier) + ++nodeStatSimple[ndkPrivateIdentifier]; + } + void VisitorAsgStat::visit(const expression::Property& node,bool callVirtualBase ) { VisitorAbstractNodes::visit(node,callVirtualBase); @@ -903,6 +945,14 @@ const unsigned short VisitorAsgStat::nodeSizes[] = { ++nodeStatSimple[ndkModuleSpecifier]; } + void VisitorAsgStat::visit(const structure::PropertyDefinition& node,bool callVirtualBase ) { + VisitorAbstractNodes::visit(node,callVirtualBase); + + ++nodeStatParent[ndkPropertyDefinition]; + if (node.getNodeKind() == ndkPropertyDefinition) + ++nodeStatSimple[ndkPropertyDefinition]; + } + void VisitorAsgStat::visitPositioned_Comments(const base::Positioned& begin, const base::Comment& end) { ++edgeStat[edkPositioned_Comments]; } @@ -919,6 +969,10 @@ const unsigned short VisitorAsgStat::nodeSizes[] = { ++edgeStat[edkExportAllDeclaration_HasSource]; } + void VisitorAsgStat::visitExportAllDeclaration_HasExported(const declaration::ExportAllDeclaration& begin, const expression::Identifier& end) { + ++edgeStat[edkExportAllDeclaration_HasExported]; + } + void VisitorAsgStat::visitExportDefaultDeclaration_HasDeclaration(const declaration::ExportDefaultDeclaration& begin, const base::Positioned& end) { ++edgeStat[edkExportDefaultDeclaration_HasDeclaration]; } @@ -971,7 +1025,7 @@ const unsigned short VisitorAsgStat::nodeSizes[] = { ++edgeStat[edkAwaitExpression_HasArgument]; } - void VisitorAsgStat::visitBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const expression::Expression& end) { + void VisitorAsgStat::visitBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const base::Positioned& end) { ++edgeStat[edkBinaryExpression_HasLeft]; } @@ -991,6 +1045,10 @@ const unsigned short VisitorAsgStat::nodeSizes[] = { ++edgeStat[edkCallExpression_Calls]; } + void VisitorAsgStat::visitChainExpression_HasExpression(const expression::ChainExpression& begin, const expression::ChainElement& end) { + ++edgeStat[edkChainExpression_HasExpression]; + } + void VisitorAsgStat::visitConditionalExpression_HasAlternate(const expression::ConditionalExpression& begin, const expression::Expression& end) { ++edgeStat[edkConditionalExpression_HasAlternate]; } @@ -1007,6 +1065,10 @@ const unsigned short VisitorAsgStat::nodeSizes[] = { ++edgeStat[edkIdentifier_RefersTo]; } + void VisitorAsgStat::visitImportExpression_HasSource(const expression::ImportExpression& begin, const expression::Expression& end) { + ++edgeStat[edkImportExpression_HasSource]; + } + void VisitorAsgStat::visitLogicalExpression_HasLeft(const expression::LogicalExpression& begin, const expression::Expression& end) { ++edgeStat[edkLogicalExpression_HasLeft]; } @@ -1015,7 +1077,7 @@ const unsigned short VisitorAsgStat::nodeSizes[] = { ++edgeStat[edkLogicalExpression_HasRight]; } - void VisitorAsgStat::visitMemberExpression_HasProperty(const expression::MemberExpression& begin, const expression::Expression& end) { + void VisitorAsgStat::visitMemberExpression_HasProperty(const expression::MemberExpression& begin, const base::Positioned& end) { ++edgeStat[edkMemberExpression_HasProperty]; } @@ -1259,7 +1321,7 @@ const unsigned short VisitorAsgStat::nodeSizes[] = { ++edgeStat[edkClass_HasIdentifier]; } - void VisitorAsgStat::visitClassBody_HasBody(const structure::ClassBody& begin, const structure::MethodDefinition& end) { + void VisitorAsgStat::visitClassBody_HasBody(const structure::ClassBody& begin, const base::Positioned& end) { ++edgeStat[edkClassBody_HasBody]; } @@ -1271,7 +1333,7 @@ const unsigned short VisitorAsgStat::nodeSizes[] = { ++edgeStat[edkImportSpecifier_HasImported]; } - void VisitorAsgStat::visitMethodDefinition_HasKey(const structure::MethodDefinition& begin, const expression::Expression& end) { + void VisitorAsgStat::visitMethodDefinition_HasKey(const structure::MethodDefinition& begin, const base::Positioned& end) { ++edgeStat[edkMethodDefinition_HasKey]; } @@ -1283,5 +1345,13 @@ const unsigned short VisitorAsgStat::nodeSizes[] = { ++edgeStat[edkModuleSpecifier_HasLocal]; } + void VisitorAsgStat::visitPropertyDefinition_HasKey(const structure::PropertyDefinition& begin, const base::Positioned& end) { + ++edgeStat[edkPropertyDefinition_HasKey]; + } + + void VisitorAsgStat::visitPropertyDefinition_HasValue(const structure::PropertyDefinition& begin, const expression::Expression& end) { + ++edgeStat[edkPropertyDefinition_HasValue]; + } + }}} diff --git a/lib/javascript/src/visitors/VisitorFilter.cpp b/lib/javascript/src/visitors/VisitorFilter.cpp index 275ddd0..bbbc568 100644 --- a/lib/javascript/src/visitors/VisitorFilter.cpp +++ b/lib/javascript/src/visitors/VisitorFilter.cpp @@ -88,11 +88,11 @@ void VisitorFilter::visitEnd(const expression::AssignmentExpression& node , bool (node.getFactory().*selector)(node.getId()); } -void VisitorFilter::visitEnd(const expression::AssignmentProperty& node , bool callVirtualBase /*= true*/) { +void VisitorFilter::visitEnd(const expression::AwaitExpression& node , bool callVirtualBase /*= true*/) { (node.getFactory().*selector)(node.getId()); } -void VisitorFilter::visitEnd(const expression::AwaitExpression& node , bool callVirtualBase /*= true*/) { +void VisitorFilter::visitEnd(const expression::BigIntLiteral& node , bool callVirtualBase /*= true*/) { (node.getFactory().*selector)(node.getId()); } @@ -108,6 +108,14 @@ void VisitorFilter::visitEnd(const expression::CallExpression& node , bool callV (node.getFactory().*selector)(node.getId()); } +void VisitorFilter::visitEnd(const expression::ChainElement& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::ChainExpression& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + void VisitorFilter::visitEnd(const expression::ClassExpression& node , bool callVirtualBase /*= true*/) { (node.getFactory().*selector)(node.getId()); } @@ -124,6 +132,10 @@ void VisitorFilter::visitEnd(const expression::Identifier& node , bool callVirtu (node.getFactory().*selector)(node.getId()); } +void VisitorFilter::visitEnd(const expression::ImportExpression& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + void VisitorFilter::visitEnd(const expression::LogicalExpression& node , bool callVirtualBase /*= true*/) { (node.getFactory().*selector)(node.getId()); } @@ -152,6 +164,10 @@ void VisitorFilter::visitEnd(const expression::ObjectExpression& node , bool cal (node.getFactory().*selector)(node.getId()); } +void VisitorFilter::visitEnd(const expression::PrivateIdentifier& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + void VisitorFilter::visitEnd(const expression::Property& node , bool callVirtualBase /*= true*/) { (node.getFactory().*selector)(node.getId()); } @@ -328,5 +344,9 @@ void VisitorFilter::visitEnd(const structure::MethodDefinition& node , bool call (node.getFactory().*selector)(node.getId()); } +void VisitorFilter::visitEnd(const structure::PropertyDefinition& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + }}} diff --git a/lib/javascript/src/visitors/VisitorGraphml.cpp b/lib/javascript/src/visitors/VisitorGraphml.cpp index db30b32..1dc668f 100644 --- a/lib/javascript/src/visitors/VisitorGraphml.cpp +++ b/lib/javascript/src/visitors/VisitorGraphml.cpp @@ -332,23 +332,27 @@ void VisitorGraphml::addAttributeToContent(const expression::AssignmentExpressio content += "operator : " + Common::toString(node.getOperator()) + "\n"; } -void VisitorGraphml::addAttributeToContent(const expression::AssignmentProperty& node, std::string& content, bool callVirtualBase) { - addAttributeToContent(static_cast(node), content, false); - if ( !((nodeTypeAttributeFilter.empty()) || ( nodeTypeAttributeFilter.find("expression::AssignmentProperty") != nodeTypeAttributeFilter.end()))) +void VisitorGraphml::addAttributeToContent(const expression::AwaitExpression& node, std::string& content, bool callVirtualBase) { + if (callVirtualBase) { + addAttributeToContent(static_cast(node), content, false); + } + addAttributeToContent(static_cast(node), content, false); + if ( !((nodeTypeAttributeFilter.empty()) || ( nodeTypeAttributeFilter.find("expression::AwaitExpression") != nodeTypeAttributeFilter.end()))) { return; } } -void VisitorGraphml::addAttributeToContent(const expression::AwaitExpression& node, std::string& content, bool callVirtualBase) { +void VisitorGraphml::addAttributeToContent(const expression::BigIntLiteral& node, std::string& content, bool callVirtualBase) { if (callVirtualBase) { addAttributeToContent(static_cast(node), content, false); } - addAttributeToContent(static_cast(node), content, false); - if ( !((nodeTypeAttributeFilter.empty()) || ( nodeTypeAttributeFilter.find("expression::AwaitExpression") != nodeTypeAttributeFilter.end()))) + addAttributeToContent(static_cast(node), content, false); + if ( !((nodeTypeAttributeFilter.empty()) || ( nodeTypeAttributeFilter.find("expression::BigIntLiteral") != nodeTypeAttributeFilter.end()))) { return; } + content += "bigint : " + node.getBigint() + "\n"; } void VisitorGraphml::addAttributeToContent(const expression::BinaryExpression& node, std::string& content, bool callVirtualBase) { @@ -380,12 +384,35 @@ void VisitorGraphml::addAttributeToContent(const expression::CallExpression& nod addAttributeToContent(static_cast(node), content, false); } addAttributeToContent(static_cast(node), content, false); + addAttributeToContent(static_cast(node), content, false); if ( !((nodeTypeAttributeFilter.empty()) || ( nodeTypeAttributeFilter.find("expression::CallExpression") != nodeTypeAttributeFilter.end()))) { return; } } +void VisitorGraphml::addAttributeToContent(const expression::ChainElement& node, std::string& content, bool callVirtualBase) { + if (callVirtualBase) { + addAttributeToContent(static_cast(node), content, false); + } + if ( !((nodeTypeAttributeFilter.empty()) || ( nodeTypeAttributeFilter.find("expression::ChainElement") != nodeTypeAttributeFilter.end()))) + { + return; + } + content += "optional : " + std::string(node.getOptional() ? "true" : "false") + "\n"; +} + +void VisitorGraphml::addAttributeToContent(const expression::ChainExpression& node, std::string& content, bool callVirtualBase) { + if (callVirtualBase) { + addAttributeToContent(static_cast(node), content, false); + } + addAttributeToContent(static_cast(node), content, false); + if ( !((nodeTypeAttributeFilter.empty()) || ( nodeTypeAttributeFilter.find("expression::ChainExpression") != nodeTypeAttributeFilter.end()))) + { + return; + } +} + void VisitorGraphml::addAttributeToContent(const expression::ClassExpression& node, std::string& content, bool callVirtualBase) { if (callVirtualBase) { addAttributeToContent(static_cast(node), content, false); @@ -445,6 +472,17 @@ void VisitorGraphml::addAttributeToContent(const expression::Identifier& node, s } } +void VisitorGraphml::addAttributeToContent(const expression::ImportExpression& node, std::string& content, bool callVirtualBase) { + if (callVirtualBase) { + addAttributeToContent(static_cast(node), content, false); + } + addAttributeToContent(static_cast(node), content, false); + if ( !((nodeTypeAttributeFilter.empty()) || ( nodeTypeAttributeFilter.find("expression::ImportExpression") != nodeTypeAttributeFilter.end()))) + { + return; + } +} + void VisitorGraphml::addAttributeToContent(const expression::Literal& node, std::string& content, bool callVirtualBase) { if (callVirtualBase) { addAttributeToContent(static_cast(node), content, false); @@ -475,6 +513,7 @@ void VisitorGraphml::addAttributeToContent(const expression::MemberExpression& n } addAttributeToContent(static_cast(node), content, false); addAttributeToContent(static_cast(node), content, false); + addAttributeToContent(static_cast(node), content, false); if ( !((nodeTypeAttributeFilter.empty()) || ( nodeTypeAttributeFilter.find("expression::MemberExpression") != nodeTypeAttributeFilter.end()))) { return; @@ -538,6 +577,17 @@ void VisitorGraphml::addAttributeToContent(const expression::ObjectExpression& n } } +void VisitorGraphml::addAttributeToContent(const expression::PrivateIdentifier& node, std::string& content, bool callVirtualBase) { + if (callVirtualBase) { + addAttributeToContent(static_cast(node), content, false); + } + addAttributeToContent(static_cast(node), content, false); + if ( !((nodeTypeAttributeFilter.empty()) || ( nodeTypeAttributeFilter.find("expression::PrivateIdentifier") != nodeTypeAttributeFilter.end()))) + { + return; + } +} + void VisitorGraphml::addAttributeToContent(const expression::Property& node, std::string& content, bool callVirtualBase) { addAttributeToContent(static_cast(node), content, false); if ( !((nodeTypeAttributeFilter.empty()) || ( nodeTypeAttributeFilter.find("expression::Property") != nodeTypeAttributeFilter.end()))) @@ -811,7 +861,7 @@ void VisitorGraphml::addAttributeToContent(const statement::ForOfStatement& node { return; } - content += "async : " + std::string(node.getAsync() ? "true" : "false") + "\n"; + content += "await : " + std::string(node.getAwait() ? "true" : "false") + "\n"; } void VisitorGraphml::addAttributeToContent(const statement::ForStatement& node, std::string& content, bool callVirtualBase) { @@ -1052,6 +1102,16 @@ void VisitorGraphml::addAttributeToContent(const structure::ModuleSpecifier& nod } } +void VisitorGraphml::addAttributeToContent(const structure::PropertyDefinition& node, std::string& content, bool callVirtualBase) { + addAttributeToContent(static_cast(node), content, false); + if ( !((nodeTypeAttributeFilter.empty()) || ( nodeTypeAttributeFilter.find("structure::PropertyDefinition") != nodeTypeAttributeFilter.end()))) + { + return; + } + content += "computed : " + std::string(node.getComputed() ? "true" : "false") + "\n"; + content += "static : " + std::string(node.getStatic() ? "true" : "false") + "\n"; +} + void VisitorGraphml::visit(const base::Comment& node, bool callVirtualBase) { if ( !((nodeTypeFilter.empty()) || ( nodeTypeFilter.find("base::Comment") == nodeTypeFilter.end()))) { @@ -1334,7 +1394,7 @@ void VisitorGraphml::visit(const declaration::ExportAllDeclaration& node, bool c parentNodeStack.push_front(node.getParent()->getId()); } bool hasChildNode = false; - if(node.getSource()) + if(node.getSource() || node.getExported()) hasChildNode = true; if(hasChildNode){ io.writeGroupNodeBegin(Common::toString(node.getId()), title, content, titleBGColor, "", fillColor); @@ -1994,8 +2054,8 @@ void VisitorGraphml::visitEnd(const expression::AssignmentExpression& node, bool } } -void VisitorGraphml::visit(const expression::AssignmentProperty& node, bool callVirtualBase) { - if ( !((nodeTypeFilter.empty()) || ( nodeTypeFilter.find("expression::AssignmentProperty") == nodeTypeFilter.end()))) +void VisitorGraphml::visit(const expression::AwaitExpression& node, bool callVirtualBase) { + if ( !((nodeTypeFilter.empty()) || ( nodeTypeFilter.find("expression::AwaitExpression") == nodeTypeFilter.end()))) { return; } @@ -2011,7 +2071,7 @@ void VisitorGraphml::visit(const expression::AssignmentProperty& node, bool call return; } std::string content; - std::string title("expression::AssignmentProperty"); + std::string title("expression::AwaitExpression"); std::string titleBGColor("#ccccff"); std::string fillColor("#ccffff"); addAttributeToContent(node, content, true); @@ -2029,7 +2089,7 @@ void VisitorGraphml::visit(const expression::AssignmentProperty& node, bool call parentNodeStack.push_front(node.getParent()->getId()); } bool hasChildNode = false; - if(node.getValue() || node.getKey()) + if(node.getArgument()) hasChildNode = true; if(hasChildNode){ io.writeGroupNodeBegin(Common::toString(node.getId()), title, content, titleBGColor, "", fillColor); @@ -2042,8 +2102,8 @@ void VisitorGraphml::visit(const expression::AssignmentProperty& node, bool call lastVisitedNodeId = node.getId(); } -void VisitorGraphml::visitEnd(const expression::AssignmentProperty& node, bool callVirtualBase) { - if ( !((nodeTypeFilter.empty()) || ( nodeTypeFilter.find("expression::AssignmentProperty") == nodeTypeFilter.end()))) +void VisitorGraphml::visitEnd(const expression::AwaitExpression& node, bool callVirtualBase) { + if ( !((nodeTypeFilter.empty()) || ( nodeTypeFilter.find("expression::AwaitExpression") == nodeTypeFilter.end()))) { return; } @@ -2058,8 +2118,8 @@ void VisitorGraphml::visitEnd(const expression::AssignmentProperty& node, bool c } } -void VisitorGraphml::visit(const expression::AwaitExpression& node, bool callVirtualBase) { - if ( !((nodeTypeFilter.empty()) || ( nodeTypeFilter.find("expression::AwaitExpression") == nodeTypeFilter.end()))) +void VisitorGraphml::visit(const expression::BigIntLiteral& node, bool callVirtualBase) { + if ( !((nodeTypeFilter.empty()) || ( nodeTypeFilter.find("expression::BigIntLiteral") == nodeTypeFilter.end()))) { return; } @@ -2075,7 +2135,7 @@ void VisitorGraphml::visit(const expression::AwaitExpression& node, bool callVir return; } std::string content; - std::string title("expression::AwaitExpression"); + std::string title("expression::BigIntLiteral"); std::string titleBGColor("#ccccff"); std::string fillColor("#ccffff"); addAttributeToContent(node, content, true); @@ -2092,28 +2152,19 @@ void VisitorGraphml::visit(const expression::AwaitExpression& node, bool callVir edgeKindStack.push_front(node.getParentEdgeKind()); parentNodeStack.push_front(node.getParent()->getId()); } - bool hasChildNode = false; - if(node.getArgument()) - hasChildNode = true; - if(hasChildNode){ - io.writeGroupNodeBegin(Common::toString(node.getId()), title, content, titleBGColor, "", fillColor); - }else{ - io.writeNode(Common::toString(node.getId()), title, content, titleBGColor, "", fillColor); - } + io.writeNode(Common::toString(node.getId()), title, content, titleBGColor, "", fillColor); }else{ io.writeNode(Common::toString(node.getId()), title, content, titleBGColor, "", fillColor); } lastVisitedNodeId = node.getId(); } -void VisitorGraphml::visitEnd(const expression::AwaitExpression& node, bool callVirtualBase) { - if ( !((nodeTypeFilter.empty()) || ( nodeTypeFilter.find("expression::AwaitExpression") == nodeTypeFilter.end()))) +void VisitorGraphml::visitEnd(const expression::BigIntLiteral& node, bool callVirtualBase) { + if ( !((nodeTypeFilter.empty()) || ( nodeTypeFilter.find("expression::BigIntLiteral") == nodeTypeFilter.end()))) { return; } if(isGroupingTreeNodes){ - if(lastVisitedNodeId != node.getId()) - io.writeGroupNodeEnd(); if(edgeKindStack.begin()!=edgeKindStack.end() && (*(edgeKindStack.begin()) != node.getParentEdgeKind() || *(parentNodeStack.begin()) != node.getParent()->getId())){ io.writeGroupNodeEnd(); edgeKindStack.pop_front(); @@ -2305,6 +2356,125 @@ void VisitorGraphml::visitEnd(const expression::CallExpression& node, bool callV } } +void VisitorGraphml::visit(const expression::ChainElement& node, bool callVirtualBase) { + if ( !((nodeTypeFilter.empty()) || ( nodeTypeFilter.find("expression::ChainElement") == nodeTypeFilter.end()))) + { + return; + } + if ( maxDrawingDepth > 0) + { + std::map::iterator foundDrawedNode = idsToDrawedNodes.find( node.getId()); + if ( foundDrawedNode != idsToDrawedNodes.end()) + if (foundDrawedNode->second) + return; + else + foundDrawedNode->second = true; + else + return; + } + std::string content; + std::string title("expression::ChainElement"); + std::string titleBGColor("#ccccff"); + std::string fillColor("#ccffff"); + addAttributeToContent(node, content, true); + compositeContentFormatter(content); + if(isGroupingTreeNodes){ + if(edgeKindStack.begin() != edgeKindStack.end() && *(edgeKindStack.begin()) != node.getParentEdgeKind() && node.getParent() && *(parentNodeStack.begin()) == node.getParent()->getId()){ + io.writeGroupNodeEnd(); + edgeKindStack.pop_front(); + parentNodeStack.pop_front(); + } + if(node.getParent() && (edgeKindStack.begin() == edgeKindStack.end() || (edgeKindStack.begin() != edgeKindStack.end() && (*(edgeKindStack.begin()) != node.getParentEdgeKind() || *(parentNodeStack.begin()) != node.getParent()->getId())))){ + std::string edgename = Common::toString(node.getParentEdgeKind()); + io.writeGroupNodeBegin(Common::toString(node.getParent()->getId())+edgename.substr(edgename.find('_')), edgename.substr(edgename.find('_')+1), "", titleBGColor, "", titleBGColor); + edgeKindStack.push_front(node.getParentEdgeKind()); + parentNodeStack.push_front(node.getParent()->getId()); + } + io.writeNode(Common::toString(node.getId()), title, content, titleBGColor, "", fillColor); + }else{ + io.writeNode(Common::toString(node.getId()), title, content, titleBGColor, "", fillColor); + } + lastVisitedNodeId = node.getId(); +} + +void VisitorGraphml::visitEnd(const expression::ChainElement& node, bool callVirtualBase) { + if ( !((nodeTypeFilter.empty()) || ( nodeTypeFilter.find("expression::ChainElement") == nodeTypeFilter.end()))) + { + return; + } + if(isGroupingTreeNodes){ + if(edgeKindStack.begin()!=edgeKindStack.end() && (*(edgeKindStack.begin()) != node.getParentEdgeKind() || *(parentNodeStack.begin()) != node.getParent()->getId())){ + io.writeGroupNodeEnd(); + edgeKindStack.pop_front(); + parentNodeStack.pop_front(); + } + } +} + +void VisitorGraphml::visit(const expression::ChainExpression& node, bool callVirtualBase) { + if ( !((nodeTypeFilter.empty()) || ( nodeTypeFilter.find("expression::ChainExpression") == nodeTypeFilter.end()))) + { + return; + } + if ( maxDrawingDepth > 0) + { + std::map::iterator foundDrawedNode = idsToDrawedNodes.find( node.getId()); + if ( foundDrawedNode != idsToDrawedNodes.end()) + if (foundDrawedNode->second) + return; + else + foundDrawedNode->second = true; + else + return; + } + std::string content; + std::string title("expression::ChainExpression"); + std::string titleBGColor("#ccccff"); + std::string fillColor("#ccffff"); + addAttributeToContent(node, content, true); + compositeContentFormatter(content); + if(isGroupingTreeNodes){ + if(edgeKindStack.begin() != edgeKindStack.end() && *(edgeKindStack.begin()) != node.getParentEdgeKind() && node.getParent() && *(parentNodeStack.begin()) == node.getParent()->getId()){ + io.writeGroupNodeEnd(); + edgeKindStack.pop_front(); + parentNodeStack.pop_front(); + } + if(node.getParent() && (edgeKindStack.begin() == edgeKindStack.end() || (edgeKindStack.begin() != edgeKindStack.end() && (*(edgeKindStack.begin()) != node.getParentEdgeKind() || *(parentNodeStack.begin()) != node.getParent()->getId())))){ + std::string edgename = Common::toString(node.getParentEdgeKind()); + io.writeGroupNodeBegin(Common::toString(node.getParent()->getId())+edgename.substr(edgename.find('_')), edgename.substr(edgename.find('_')+1), "", titleBGColor, "", titleBGColor); + edgeKindStack.push_front(node.getParentEdgeKind()); + parentNodeStack.push_front(node.getParent()->getId()); + } + bool hasChildNode = false; + if(node.getExpression()) + hasChildNode = true; + if(hasChildNode){ + io.writeGroupNodeBegin(Common::toString(node.getId()), title, content, titleBGColor, "", fillColor); + }else{ + io.writeNode(Common::toString(node.getId()), title, content, titleBGColor, "", fillColor); + } + }else{ + io.writeNode(Common::toString(node.getId()), title, content, titleBGColor, "", fillColor); + } + lastVisitedNodeId = node.getId(); +} + +void VisitorGraphml::visitEnd(const expression::ChainExpression& node, bool callVirtualBase) { + if ( !((nodeTypeFilter.empty()) || ( nodeTypeFilter.find("expression::ChainExpression") == nodeTypeFilter.end()))) + { + return; + } + if(isGroupingTreeNodes){ + if(lastVisitedNodeId != node.getId()) + io.writeGroupNodeEnd(); + if(edgeKindStack.begin()!=edgeKindStack.end() && (*(edgeKindStack.begin()) != node.getParentEdgeKind() || *(parentNodeStack.begin()) != node.getParent()->getId())){ + io.writeGroupNodeEnd(); + edgeKindStack.pop_front(); + parentNodeStack.pop_front(); + } + } +} + void VisitorGraphml::visit(const expression::ClassExpression& node, bool callVirtualBase) { if ( !((nodeTypeFilter.empty()) || ( nodeTypeFilter.find("expression::ClassExpression") == nodeTypeFilter.end()))) { @@ -2552,6 +2722,70 @@ void VisitorGraphml::visitEnd(const expression::Identifier& node, bool callVirtu } } +void VisitorGraphml::visit(const expression::ImportExpression& node, bool callVirtualBase) { + if ( !((nodeTypeFilter.empty()) || ( nodeTypeFilter.find("expression::ImportExpression") == nodeTypeFilter.end()))) + { + return; + } + if ( maxDrawingDepth > 0) + { + std::map::iterator foundDrawedNode = idsToDrawedNodes.find( node.getId()); + if ( foundDrawedNode != idsToDrawedNodes.end()) + if (foundDrawedNode->second) + return; + else + foundDrawedNode->second = true; + else + return; + } + std::string content; + std::string title("expression::ImportExpression"); + std::string titleBGColor("#ccccff"); + std::string fillColor("#ccffff"); + addAttributeToContent(node, content, true); + compositeContentFormatter(content); + if(isGroupingTreeNodes){ + if(edgeKindStack.begin() != edgeKindStack.end() && *(edgeKindStack.begin()) != node.getParentEdgeKind() && node.getParent() && *(parentNodeStack.begin()) == node.getParent()->getId()){ + io.writeGroupNodeEnd(); + edgeKindStack.pop_front(); + parentNodeStack.pop_front(); + } + if(node.getParent() && (edgeKindStack.begin() == edgeKindStack.end() || (edgeKindStack.begin() != edgeKindStack.end() && (*(edgeKindStack.begin()) != node.getParentEdgeKind() || *(parentNodeStack.begin()) != node.getParent()->getId())))){ + std::string edgename = Common::toString(node.getParentEdgeKind()); + io.writeGroupNodeBegin(Common::toString(node.getParent()->getId())+edgename.substr(edgename.find('_')), edgename.substr(edgename.find('_')+1), "", titleBGColor, "", titleBGColor); + edgeKindStack.push_front(node.getParentEdgeKind()); + parentNodeStack.push_front(node.getParent()->getId()); + } + bool hasChildNode = false; + if(node.getSource()) + hasChildNode = true; + if(hasChildNode){ + io.writeGroupNodeBegin(Common::toString(node.getId()), title, content, titleBGColor, "", fillColor); + }else{ + io.writeNode(Common::toString(node.getId()), title, content, titleBGColor, "", fillColor); + } + }else{ + io.writeNode(Common::toString(node.getId()), title, content, titleBGColor, "", fillColor); + } + lastVisitedNodeId = node.getId(); +} + +void VisitorGraphml::visitEnd(const expression::ImportExpression& node, bool callVirtualBase) { + if ( !((nodeTypeFilter.empty()) || ( nodeTypeFilter.find("expression::ImportExpression") == nodeTypeFilter.end()))) + { + return; + } + if(isGroupingTreeNodes){ + if(lastVisitedNodeId != node.getId()) + io.writeGroupNodeEnd(); + if(edgeKindStack.begin()!=edgeKindStack.end() && (*(edgeKindStack.begin()) != node.getParentEdgeKind() || *(parentNodeStack.begin()) != node.getParent()->getId())){ + io.writeGroupNodeEnd(); + edgeKindStack.pop_front(); + parentNodeStack.pop_front(); + } + } +} + void VisitorGraphml::visit(const expression::LogicalExpression& node, bool callVirtualBase) { if ( !((nodeTypeFilter.empty()) || ( nodeTypeFilter.find("expression::LogicalExpression") == nodeTypeFilter.end()))) { @@ -2982,6 +3216,61 @@ void VisitorGraphml::visitEnd(const expression::ObjectExpression& node, bool cal } } +void VisitorGraphml::visit(const expression::PrivateIdentifier& node, bool callVirtualBase) { + if ( !((nodeTypeFilter.empty()) || ( nodeTypeFilter.find("expression::PrivateIdentifier") == nodeTypeFilter.end()))) + { + return; + } + if ( maxDrawingDepth > 0) + { + std::map::iterator foundDrawedNode = idsToDrawedNodes.find( node.getId()); + if ( foundDrawedNode != idsToDrawedNodes.end()) + if (foundDrawedNode->second) + return; + else + foundDrawedNode->second = true; + else + return; + } + std::string content; + std::string title("expression::PrivateIdentifier"); + std::string titleBGColor("#ccccff"); + std::string fillColor("#ccffff"); + addAttributeToContent(node, content, true); + compositeContentFormatter(content); + if(isGroupingTreeNodes){ + if(edgeKindStack.begin() != edgeKindStack.end() && *(edgeKindStack.begin()) != node.getParentEdgeKind() && node.getParent() && *(parentNodeStack.begin()) == node.getParent()->getId()){ + io.writeGroupNodeEnd(); + edgeKindStack.pop_front(); + parentNodeStack.pop_front(); + } + if(node.getParent() && (edgeKindStack.begin() == edgeKindStack.end() || (edgeKindStack.begin() != edgeKindStack.end() && (*(edgeKindStack.begin()) != node.getParentEdgeKind() || *(parentNodeStack.begin()) != node.getParent()->getId())))){ + std::string edgename = Common::toString(node.getParentEdgeKind()); + io.writeGroupNodeBegin(Common::toString(node.getParent()->getId())+edgename.substr(edgename.find('_')), edgename.substr(edgename.find('_')+1), "", titleBGColor, "", titleBGColor); + edgeKindStack.push_front(node.getParentEdgeKind()); + parentNodeStack.push_front(node.getParent()->getId()); + } + io.writeNode(Common::toString(node.getId()), title, content, titleBGColor, "", fillColor); + }else{ + io.writeNode(Common::toString(node.getId()), title, content, titleBGColor, "", fillColor); + } + lastVisitedNodeId = node.getId(); +} + +void VisitorGraphml::visitEnd(const expression::PrivateIdentifier& node, bool callVirtualBase) { + if ( !((nodeTypeFilter.empty()) || ( nodeTypeFilter.find("expression::PrivateIdentifier") == nodeTypeFilter.end()))) + { + return; + } + if(isGroupingTreeNodes){ + if(edgeKindStack.begin()!=edgeKindStack.end() && (*(edgeKindStack.begin()) != node.getParentEdgeKind() || *(parentNodeStack.begin()) != node.getParent()->getId())){ + io.writeGroupNodeEnd(); + edgeKindStack.pop_front(); + parentNodeStack.pop_front(); + } + } +} + void VisitorGraphml::visit(const expression::Property& node, bool callVirtualBase) { if ( !((nodeTypeFilter.empty()) || ( nodeTypeFilter.find("expression::Property") == nodeTypeFilter.end()))) { @@ -5739,6 +6028,70 @@ void VisitorGraphml::visitEnd(const structure::MethodDefinition& node, bool call } } +void VisitorGraphml::visit(const structure::PropertyDefinition& node, bool callVirtualBase) { + if ( !((nodeTypeFilter.empty()) || ( nodeTypeFilter.find("structure::PropertyDefinition") == nodeTypeFilter.end()))) + { + return; + } + if ( maxDrawingDepth > 0) + { + std::map::iterator foundDrawedNode = idsToDrawedNodes.find( node.getId()); + if ( foundDrawedNode != idsToDrawedNodes.end()) + if (foundDrawedNode->second) + return; + else + foundDrawedNode->second = true; + else + return; + } + std::string content; + std::string title("structure::PropertyDefinition"); + std::string titleBGColor("#ccccff"); + std::string fillColor("#ccffff"); + addAttributeToContent(node, content, true); + compositeContentFormatter(content); + if(isGroupingTreeNodes){ + if(edgeKindStack.begin() != edgeKindStack.end() && *(edgeKindStack.begin()) != node.getParentEdgeKind() && node.getParent() && *(parentNodeStack.begin()) == node.getParent()->getId()){ + io.writeGroupNodeEnd(); + edgeKindStack.pop_front(); + parentNodeStack.pop_front(); + } + if(node.getParent() && (edgeKindStack.begin() == edgeKindStack.end() || (edgeKindStack.begin() != edgeKindStack.end() && (*(edgeKindStack.begin()) != node.getParentEdgeKind() || *(parentNodeStack.begin()) != node.getParent()->getId())))){ + std::string edgename = Common::toString(node.getParentEdgeKind()); + io.writeGroupNodeBegin(Common::toString(node.getParent()->getId())+edgename.substr(edgename.find('_')), edgename.substr(edgename.find('_')+1), "", titleBGColor, "", titleBGColor); + edgeKindStack.push_front(node.getParentEdgeKind()); + parentNodeStack.push_front(node.getParent()->getId()); + } + bool hasChildNode = false; + if(node.getKey() || node.getValue()) + hasChildNode = true; + if(hasChildNode){ + io.writeGroupNodeBegin(Common::toString(node.getId()), title, content, titleBGColor, "", fillColor); + }else{ + io.writeNode(Common::toString(node.getId()), title, content, titleBGColor, "", fillColor); + } + }else{ + io.writeNode(Common::toString(node.getId()), title, content, titleBGColor, "", fillColor); + } + lastVisitedNodeId = node.getId(); +} + +void VisitorGraphml::visitEnd(const structure::PropertyDefinition& node, bool callVirtualBase) { + if ( !((nodeTypeFilter.empty()) || ( nodeTypeFilter.find("structure::PropertyDefinition") == nodeTypeFilter.end()))) + { + return; + } + if(isGroupingTreeNodes){ + if(lastVisitedNodeId != node.getId()) + io.writeGroupNodeEnd(); + if(edgeKindStack.begin()!=edgeKindStack.end() && (*(edgeKindStack.begin()) != node.getParentEdgeKind() || *(parentNodeStack.begin()) != node.getParent()->getId())){ + io.writeGroupNodeEnd(); + edgeKindStack.pop_front(); + parentNodeStack.pop_front(); + } + } +} + void VisitorGraphml::visitPositioned_Comments(const base::Positioned& begin, const base::Comment& end) { if (!visitCrossEdge) return; @@ -5843,6 +6196,32 @@ void VisitorGraphml::visitExportAllDeclaration_HasSource(const declaration::Exp idsToDrawedNodes.insert( std::make_pair( end.getId(),false)); } +void VisitorGraphml::visitExportAllDeclaration_HasExported(const declaration::ExportAllDeclaration& begin, const expression::Identifier& end) { + if(isGroupingTreeNodes) + return; + if ( (this->getDepth() >= maxDrawingDepth) && ( maxDrawingDepth > 0)) + return; + if ( !((edgeFilter.empty()) || ( edgeFilter.find("ExportAllDeclaration_HasExported") != edgeFilter.end()))) + { + return; + } + if ( maxDrawingDepth > 0) + { + std::map::iterator foundDrawedNode = idsToDrawedNodes.find( begin.getId()); + if ( foundDrawedNode == idsToDrawedNodes.end()) + return; + } + if ( !((nodeTypeFilter.empty()) || (nodeTypeFilter.find("declaration::ExportAllDeclaration") == nodeTypeFilter.end() && nodeTypeFilter.find("expression::Identifier") == nodeTypeFilter.end()))) + { + return; + } + if(isGroupingTreeNodes) + io.writeEdgeBuffer(Common::toString(begin.getId()), Common::toString(end.getId()), "ExportAllDeclaration_HasExported", 1, GraphmlIO::ls_line, GraphmlIO::at_diamond, GraphmlIO::at_none); + else + io.writeEdge(Common::toString(begin.getId()), Common::toString(end.getId()), "ExportAllDeclaration_HasExported", 1, GraphmlIO::ls_line, GraphmlIO::at_diamond, GraphmlIO::at_none); + idsToDrawedNodes.insert( std::make_pair( end.getId(),false)); +} + void VisitorGraphml::visitExportDefaultDeclaration_HasDeclaration(const declaration::ExportDefaultDeclaration& begin, const base::Positioned& end) { if(isGroupingTreeNodes) return; @@ -6181,7 +6560,7 @@ void VisitorGraphml::visitAwaitExpression_HasArgument(const expression::AwaitEx idsToDrawedNodes.insert( std::make_pair( end.getId(),false)); } -void VisitorGraphml::visitBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const expression::Expression& end) { +void VisitorGraphml::visitBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const base::Positioned& end) { if(isGroupingTreeNodes) return; if ( (this->getDepth() >= maxDrawingDepth) && ( maxDrawingDepth > 0)) @@ -6196,7 +6575,7 @@ void VisitorGraphml::visitBinaryExpression_HasLeft(const expression::BinaryExpr if ( foundDrawedNode == idsToDrawedNodes.end()) return; } - if ( !((nodeTypeFilter.empty()) || (nodeTypeFilter.find("expression::BinaryExpression") == nodeTypeFilter.end() && nodeTypeFilter.find("expression::Expression") == nodeTypeFilter.end()))) + if ( !((nodeTypeFilter.empty()) || (nodeTypeFilter.find("expression::BinaryExpression") == nodeTypeFilter.end() && nodeTypeFilter.find("base::Positioned") == nodeTypeFilter.end()))) { return; } @@ -6311,6 +6690,32 @@ void VisitorGraphml::visitCallExpression_Calls(const expression::CallExpression idsToDrawedNodes.insert( std::make_pair( end.getId(),false)); } +void VisitorGraphml::visitChainExpression_HasExpression(const expression::ChainExpression& begin, const expression::ChainElement& end) { + if(isGroupingTreeNodes) + return; + if ( (this->getDepth() >= maxDrawingDepth) && ( maxDrawingDepth > 0)) + return; + if ( !((edgeFilter.empty()) || ( edgeFilter.find("ChainExpression_HasExpression") != edgeFilter.end()))) + { + return; + } + if ( maxDrawingDepth > 0) + { + std::map::iterator foundDrawedNode = idsToDrawedNodes.find( begin.getId()); + if ( foundDrawedNode == idsToDrawedNodes.end()) + return; + } + if ( !((nodeTypeFilter.empty()) || (nodeTypeFilter.find("expression::ChainExpression") == nodeTypeFilter.end() && nodeTypeFilter.find("expression::ChainElement") == nodeTypeFilter.end()))) + { + return; + } + if(isGroupingTreeNodes) + io.writeEdgeBuffer(Common::toString(begin.getId()), Common::toString(end.getId()), "ChainExpression_HasExpression", 1, GraphmlIO::ls_line, GraphmlIO::at_diamond, GraphmlIO::at_none); + else + io.writeEdge(Common::toString(begin.getId()), Common::toString(end.getId()), "ChainExpression_HasExpression", 1, GraphmlIO::ls_line, GraphmlIO::at_diamond, GraphmlIO::at_none); + idsToDrawedNodes.insert( std::make_pair( end.getId(),false)); +} + void VisitorGraphml::visitConditionalExpression_HasAlternate(const expression::ConditionalExpression& begin, const expression::Expression& end) { if(isGroupingTreeNodes) return; @@ -6415,6 +6820,32 @@ void VisitorGraphml::visitIdentifier_RefersTo(const expression::Identifier& beg idsToDrawedNodes.insert( std::make_pair( end.getId(),false)); } +void VisitorGraphml::visitImportExpression_HasSource(const expression::ImportExpression& begin, const expression::Expression& end) { + if(isGroupingTreeNodes) + return; + if ( (this->getDepth() >= maxDrawingDepth) && ( maxDrawingDepth > 0)) + return; + if ( !((edgeFilter.empty()) || ( edgeFilter.find("ImportExpression_HasSource") != edgeFilter.end()))) + { + return; + } + if ( maxDrawingDepth > 0) + { + std::map::iterator foundDrawedNode = idsToDrawedNodes.find( begin.getId()); + if ( foundDrawedNode == idsToDrawedNodes.end()) + return; + } + if ( !((nodeTypeFilter.empty()) || (nodeTypeFilter.find("expression::ImportExpression") == nodeTypeFilter.end() && nodeTypeFilter.find("expression::Expression") == nodeTypeFilter.end()))) + { + return; + } + if(isGroupingTreeNodes) + io.writeEdgeBuffer(Common::toString(begin.getId()), Common::toString(end.getId()), "ImportExpression_HasSource", 1, GraphmlIO::ls_line, GraphmlIO::at_diamond, GraphmlIO::at_none); + else + io.writeEdge(Common::toString(begin.getId()), Common::toString(end.getId()), "ImportExpression_HasSource", 1, GraphmlIO::ls_line, GraphmlIO::at_diamond, GraphmlIO::at_none); + idsToDrawedNodes.insert( std::make_pair( end.getId(),false)); +} + void VisitorGraphml::visitLogicalExpression_HasLeft(const expression::LogicalExpression& begin, const expression::Expression& end) { if(isGroupingTreeNodes) return; @@ -6467,7 +6898,7 @@ void VisitorGraphml::visitLogicalExpression_HasRight(const expression::LogicalE idsToDrawedNodes.insert( std::make_pair( end.getId(),false)); } -void VisitorGraphml::visitMemberExpression_HasProperty(const expression::MemberExpression& begin, const expression::Expression& end) { +void VisitorGraphml::visitMemberExpression_HasProperty(const expression::MemberExpression& begin, const base::Positioned& end) { if(isGroupingTreeNodes) return; if ( (this->getDepth() >= maxDrawingDepth) && ( maxDrawingDepth > 0)) @@ -6482,7 +6913,7 @@ void VisitorGraphml::visitMemberExpression_HasProperty(const expression::Member if ( foundDrawedNode == idsToDrawedNodes.end()) return; } - if ( !((nodeTypeFilter.empty()) || (nodeTypeFilter.find("expression::MemberExpression") == nodeTypeFilter.end() && nodeTypeFilter.find("expression::Expression") == nodeTypeFilter.end()))) + if ( !((nodeTypeFilter.empty()) || (nodeTypeFilter.find("expression::MemberExpression") == nodeTypeFilter.end() && nodeTypeFilter.find("base::Positioned") == nodeTypeFilter.end()))) { return; } @@ -8053,7 +8484,7 @@ void VisitorGraphml::visitClass_HasIdentifier(const structure::Class& begin, co idsToDrawedNodes.insert( std::make_pair( end.getId(),false)); } -void VisitorGraphml::visitClassBody_HasBody(const structure::ClassBody& begin, const structure::MethodDefinition& end) { +void VisitorGraphml::visitClassBody_HasBody(const structure::ClassBody& begin, const base::Positioned& end) { if(isGroupingTreeNodes) return; if ( (this->getDepth() >= maxDrawingDepth) && ( maxDrawingDepth > 0)) @@ -8068,7 +8499,7 @@ void VisitorGraphml::visitClassBody_HasBody(const structure::ClassBody& begin, if ( foundDrawedNode == idsToDrawedNodes.end()) return; } - if ( !((nodeTypeFilter.empty()) || (nodeTypeFilter.find("structure::ClassBody") == nodeTypeFilter.end() && nodeTypeFilter.find("structure::MethodDefinition") == nodeTypeFilter.end()))) + if ( !((nodeTypeFilter.empty()) || (nodeTypeFilter.find("structure::ClassBody") == nodeTypeFilter.end() && nodeTypeFilter.find("base::Positioned") == nodeTypeFilter.end()))) { return; } @@ -8131,7 +8562,7 @@ void VisitorGraphml::visitImportSpecifier_HasImported(const structure::ImportSp idsToDrawedNodes.insert( std::make_pair( end.getId(),false)); } -void VisitorGraphml::visitMethodDefinition_HasKey(const structure::MethodDefinition& begin, const expression::Expression& end) { +void VisitorGraphml::visitMethodDefinition_HasKey(const structure::MethodDefinition& begin, const base::Positioned& end) { if(isGroupingTreeNodes) return; if ( (this->getDepth() >= maxDrawingDepth) && ( maxDrawingDepth > 0)) @@ -8146,7 +8577,7 @@ void VisitorGraphml::visitMethodDefinition_HasKey(const structure::MethodDefini if ( foundDrawedNode == idsToDrawedNodes.end()) return; } - if ( !((nodeTypeFilter.empty()) || (nodeTypeFilter.find("structure::MethodDefinition") == nodeTypeFilter.end() && nodeTypeFilter.find("expression::Expression") == nodeTypeFilter.end()))) + if ( !((nodeTypeFilter.empty()) || (nodeTypeFilter.find("structure::MethodDefinition") == nodeTypeFilter.end() && nodeTypeFilter.find("base::Positioned") == nodeTypeFilter.end()))) { return; } @@ -8209,5 +8640,57 @@ void VisitorGraphml::visitModuleSpecifier_HasLocal(const structure::ModuleSpeci idsToDrawedNodes.insert( std::make_pair( end.getId(),false)); } +void VisitorGraphml::visitPropertyDefinition_HasKey(const structure::PropertyDefinition& begin, const base::Positioned& end) { + if(isGroupingTreeNodes) + return; + if ( (this->getDepth() >= maxDrawingDepth) && ( maxDrawingDepth > 0)) + return; + if ( !((edgeFilter.empty()) || ( edgeFilter.find("PropertyDefinition_HasKey") != edgeFilter.end()))) + { + return; + } + if ( maxDrawingDepth > 0) + { + std::map::iterator foundDrawedNode = idsToDrawedNodes.find( begin.getId()); + if ( foundDrawedNode == idsToDrawedNodes.end()) + return; + } + if ( !((nodeTypeFilter.empty()) || (nodeTypeFilter.find("structure::PropertyDefinition") == nodeTypeFilter.end() && nodeTypeFilter.find("base::Positioned") == nodeTypeFilter.end()))) + { + return; + } + if(isGroupingTreeNodes) + io.writeEdgeBuffer(Common::toString(begin.getId()), Common::toString(end.getId()), "PropertyDefinition_HasKey", 1, GraphmlIO::ls_line, GraphmlIO::at_diamond, GraphmlIO::at_none); + else + io.writeEdge(Common::toString(begin.getId()), Common::toString(end.getId()), "PropertyDefinition_HasKey", 1, GraphmlIO::ls_line, GraphmlIO::at_diamond, GraphmlIO::at_none); + idsToDrawedNodes.insert( std::make_pair( end.getId(),false)); +} + +void VisitorGraphml::visitPropertyDefinition_HasValue(const structure::PropertyDefinition& begin, const expression::Expression& end) { + if(isGroupingTreeNodes) + return; + if ( (this->getDepth() >= maxDrawingDepth) && ( maxDrawingDepth > 0)) + return; + if ( !((edgeFilter.empty()) || ( edgeFilter.find("PropertyDefinition_HasValue") != edgeFilter.end()))) + { + return; + } + if ( maxDrawingDepth > 0) + { + std::map::iterator foundDrawedNode = idsToDrawedNodes.find( begin.getId()); + if ( foundDrawedNode == idsToDrawedNodes.end()) + return; + } + if ( !((nodeTypeFilter.empty()) || (nodeTypeFilter.find("structure::PropertyDefinition") == nodeTypeFilter.end() && nodeTypeFilter.find("expression::Expression") == nodeTypeFilter.end()))) + { + return; + } + if(isGroupingTreeNodes) + io.writeEdgeBuffer(Common::toString(begin.getId()), Common::toString(end.getId()), "PropertyDefinition_HasValue", 1, GraphmlIO::ls_line, GraphmlIO::at_diamond, GraphmlIO::at_none); + else + io.writeEdge(Common::toString(begin.getId()), Common::toString(end.getId()), "PropertyDefinition_HasValue", 1, GraphmlIO::ls_line, GraphmlIO::at_diamond, GraphmlIO::at_none); + idsToDrawedNodes.insert( std::make_pair( end.getId(),false)); +} + }}} diff --git a/lib/javascript/src/visitors/VisitorJAVASCRIPTML.cpp b/lib/javascript/src/visitors/VisitorJAVASCRIPTML.cpp index 7156647..ffca851 100644 --- a/lib/javascript/src/visitors/VisitorJAVASCRIPTML.cpp +++ b/lib/javascript/src/visitors/VisitorJAVASCRIPTML.cpp @@ -260,32 +260,32 @@ void VisitorJAVASCRIPTML::visitEnd(const expression::AssignmentExpression& node ofs << "\n"; } -void VisitorJAVASCRIPTML::visit(const expression::AssignmentProperty& node , bool callVirtualBase) { +void VisitorJAVASCRIPTML::visit(const expression::AwaitExpression& node , bool callVirtualBase) { createIndentation(); - ofs << "\n"; writeAttributes(node,true,true); } -void VisitorJAVASCRIPTML::visitEnd(const expression::AssignmentProperty& node , bool callVirtualBase) { +void VisitorJAVASCRIPTML::visitEnd(const expression::AwaitExpression& node , bool callVirtualBase) { createIndentation(); - ofs << "\n"; + ofs << "\n"; } -void VisitorJAVASCRIPTML::visit(const expression::AwaitExpression& node , bool callVirtualBase) { +void VisitorJAVASCRIPTML::visit(const expression::BigIntLiteral& node , bool callVirtualBase) { createIndentation(); - ofs << "\n"; writeAttributes(node,true,true); } -void VisitorJAVASCRIPTML::visitEnd(const expression::AwaitExpression& node , bool callVirtualBase) { +void VisitorJAVASCRIPTML::visitEnd(const expression::BigIntLiteral& node , bool callVirtualBase) { createIndentation(); - ofs << "\n"; + ofs << "\n"; } void VisitorJAVASCRIPTML::visit(const expression::BinaryExpression& node , bool callVirtualBase) { @@ -330,6 +330,34 @@ void VisitorJAVASCRIPTML::visitEnd(const expression::CallExpression& node , bool ofs << "\n"; } +void VisitorJAVASCRIPTML::visit(const expression::ChainElement& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorJAVASCRIPTML::visitEnd(const expression::ChainElement& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorJAVASCRIPTML::visit(const expression::ChainExpression& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorJAVASCRIPTML::visitEnd(const expression::ChainExpression& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + void VisitorJAVASCRIPTML::visit(const expression::ClassExpression& node , bool callVirtualBase) { createIndentation(); ofs << "\n"; } +void VisitorJAVASCRIPTML::visit(const expression::ImportExpression& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorJAVASCRIPTML::visitEnd(const expression::ImportExpression& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + void VisitorJAVASCRIPTML::visit(const expression::LogicalExpression& node , bool callVirtualBase) { createIndentation(); ofs << "\n"; } +void VisitorJAVASCRIPTML::visit(const expression::PrivateIdentifier& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorJAVASCRIPTML::visitEnd(const expression::PrivateIdentifier& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + void VisitorJAVASCRIPTML::visit(const expression::Property& node , bool callVirtualBase) { createIndentation(); ofs << "\n"; } +void VisitorJAVASCRIPTML::visit(const structure::PropertyDefinition& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorJAVASCRIPTML::visitEnd(const structure::PropertyDefinition& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + void VisitorJAVASCRIPTML::visitPositioned_Comments(const base::Positioned& begin, const base::Comment& end) { createIndentation(); ofs << "insertEdge(&end, &begin, edkExportAllDeclaration_HasSource); } +void VisitorReverseEdges::visitExportAllDeclaration_HasExported(const declaration::ExportAllDeclaration& begin, const expression::Identifier& end) { + revEdges->insertEdge(&end, &begin, edkExportAllDeclaration_HasExported); +} + void VisitorReverseEdges::visitExportDefaultDeclaration_HasDeclaration(const declaration::ExportDefaultDeclaration& begin, const base::Positioned& end) { revEdges->insertEdge(&end, &begin, edkExportDefaultDeclaration_HasDeclaration); } @@ -101,7 +105,7 @@ void VisitorReverseEdges::visitAwaitExpression_HasArgument(const expression::Awa revEdges->insertEdge(&end, &begin, edkAwaitExpression_HasArgument); } -void VisitorReverseEdges::visitBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const expression::Expression& end) { +void VisitorReverseEdges::visitBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const base::Positioned& end) { revEdges->insertEdge(&end, &begin, edkBinaryExpression_HasLeft); } @@ -121,6 +125,10 @@ void VisitorReverseEdges::visitCallExpression_Calls(const expression::CallExpres revEdges->insertEdge(&end, &begin, edkCallExpression_Calls); } +void VisitorReverseEdges::visitChainExpression_HasExpression(const expression::ChainExpression& begin, const expression::ChainElement& end) { + revEdges->insertEdge(&end, &begin, edkChainExpression_HasExpression); +} + void VisitorReverseEdges::visitConditionalExpression_HasAlternate(const expression::ConditionalExpression& begin, const expression::Expression& end) { revEdges->insertEdge(&end, &begin, edkConditionalExpression_HasAlternate); } @@ -137,6 +145,10 @@ void VisitorReverseEdges::visitIdentifier_RefersTo(const expression::Identifier& revEdges->insertEdge(&end, &begin, edkIdentifier_RefersTo); } +void VisitorReverseEdges::visitImportExpression_HasSource(const expression::ImportExpression& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkImportExpression_HasSource); +} + void VisitorReverseEdges::visitLogicalExpression_HasLeft(const expression::LogicalExpression& begin, const expression::Expression& end) { revEdges->insertEdge(&end, &begin, edkLogicalExpression_HasLeft); } @@ -145,7 +157,7 @@ void VisitorReverseEdges::visitLogicalExpression_HasRight(const expression::Logi revEdges->insertEdge(&end, &begin, edkLogicalExpression_HasRight); } -void VisitorReverseEdges::visitMemberExpression_HasProperty(const expression::MemberExpression& begin, const expression::Expression& end) { +void VisitorReverseEdges::visitMemberExpression_HasProperty(const expression::MemberExpression& begin, const base::Positioned& end) { revEdges->insertEdge(&end, &begin, edkMemberExpression_HasProperty); } @@ -389,7 +401,7 @@ void VisitorReverseEdges::visitClass_HasIdentifier(const structure::Class& begin revEdges->insertEdge(&end, &begin, edkClass_HasIdentifier); } -void VisitorReverseEdges::visitClassBody_HasBody(const structure::ClassBody& begin, const structure::MethodDefinition& end) { +void VisitorReverseEdges::visitClassBody_HasBody(const structure::ClassBody& begin, const base::Positioned& end) { revEdges->insertEdge(&end, &begin, edkClassBody_HasBody); } @@ -401,7 +413,7 @@ void VisitorReverseEdges::visitImportSpecifier_HasImported(const structure::Impo revEdges->insertEdge(&end, &begin, edkImportSpecifier_HasImported); } -void VisitorReverseEdges::visitMethodDefinition_HasKey(const structure::MethodDefinition& begin, const expression::Expression& end) { +void VisitorReverseEdges::visitMethodDefinition_HasKey(const structure::MethodDefinition& begin, const base::Positioned& end) { revEdges->insertEdge(&end, &begin, edkMethodDefinition_HasKey); } @@ -413,5 +425,13 @@ void VisitorReverseEdges::visitModuleSpecifier_HasLocal(const structure::ModuleS revEdges->insertEdge(&end, &begin, edkModuleSpecifier_HasLocal); } +void VisitorReverseEdges::visitPropertyDefinition_HasKey(const structure::PropertyDefinition& begin, const base::Positioned& end) { + revEdges->insertEdge(&end, &begin, edkPropertyDefinition_HasKey); +} + +void VisitorReverseEdges::visitPropertyDefinition_HasValue(const structure::PropertyDefinition& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkPropertyDefinition_HasValue); +} + }}} diff --git a/lib/javascript/src/visitors/VisitorSimpleEdge.cpp b/lib/javascript/src/visitors/VisitorSimpleEdge.cpp index d6658eb..2a9a414 100644 --- a/lib/javascript/src/visitors/VisitorSimpleEdge.cpp +++ b/lib/javascript/src/visitors/VisitorSimpleEdge.cpp @@ -93,6 +93,22 @@ namespace columbus { namespace javascript { namespace asg { visitAllEdgeEnd (begin, end); } /** + * \brief Edge visitor for hasExported edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitExportAllDeclaration_HasExported(const declaration::ExportAllDeclaration& begin, const expression::Identifier& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasExported edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndExportAllDeclaration_HasExported(const declaration::ExportAllDeclaration& begin, const expression::Identifier& end) { + visitAllEdgeEnd (begin, end); + } + /** * \brief Edge visitor for hasDeclaration edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. @@ -305,7 +321,7 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - void VisitorSimpleEdge::visitBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const expression::Expression& end) { + void VisitorSimpleEdge::visitBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const base::Positioned& end) { visitAllEdge (begin, end); } /** @@ -313,7 +329,7 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - void VisitorSimpleEdge::visitEndBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const expression::Expression& end) { + void VisitorSimpleEdge::visitEndBinaryExpression_HasLeft(const expression::BinaryExpression& begin, const base::Positioned& end) { visitAllEdgeEnd (begin, end); } /** @@ -381,6 +397,22 @@ namespace columbus { namespace javascript { namespace asg { visitAllEdgeEnd (begin, end); } /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitChainExpression_HasExpression(const expression::ChainExpression& begin, const expression::ChainElement& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndChainExpression_HasExpression(const expression::ChainExpression& begin, const expression::ChainElement& end) { + visitAllEdgeEnd (begin, end); + } + /** * \brief Edge visitor for hasAlternate edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. @@ -445,6 +477,22 @@ namespace columbus { namespace javascript { namespace asg { visitAllEdgeEnd (begin, end); } /** + * \brief Edge visitor for hasSource edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitImportExpression_HasSource(const expression::ImportExpression& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasSource edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndImportExpression_HasSource(const expression::ImportExpression& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** * \brief Edge visitor for hasLeft edge which is called when the subtree of this edge is started. * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. @@ -481,7 +529,7 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - void VisitorSimpleEdge::visitMemberExpression_HasProperty(const expression::MemberExpression& begin, const expression::Expression& end) { + void VisitorSimpleEdge::visitMemberExpression_HasProperty(const expression::MemberExpression& begin, const base::Positioned& end) { visitAllEdge (begin, end); } /** @@ -489,7 +537,7 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - void VisitorSimpleEdge::visitEndMemberExpression_HasProperty(const expression::MemberExpression& begin, const expression::Expression& end) { + void VisitorSimpleEdge::visitEndMemberExpression_HasProperty(const expression::MemberExpression& begin, const base::Positioned& end) { visitAllEdgeEnd (begin, end); } /** @@ -1457,7 +1505,7 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - void VisitorSimpleEdge::visitClassBody_HasBody(const structure::ClassBody& begin, const structure::MethodDefinition& end) { + void VisitorSimpleEdge::visitClassBody_HasBody(const structure::ClassBody& begin, const base::Positioned& end) { visitAllEdge (begin, end); } /** @@ -1465,7 +1513,7 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - void VisitorSimpleEdge::visitEndClassBody_HasBody(const structure::ClassBody& begin, const structure::MethodDefinition& end) { + void VisitorSimpleEdge::visitEndClassBody_HasBody(const structure::ClassBody& begin, const base::Positioned& end) { visitAllEdgeEnd (begin, end); } /** @@ -1505,7 +1553,7 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - void VisitorSimpleEdge::visitMethodDefinition_HasKey(const structure::MethodDefinition& begin, const expression::Expression& end) { + void VisitorSimpleEdge::visitMethodDefinition_HasKey(const structure::MethodDefinition& begin, const base::Positioned& end) { visitAllEdge (begin, end); } /** @@ -1513,7 +1561,7 @@ namespace columbus { namespace javascript { namespace asg { * \param begin [in] The reference of the node the edge starts from. * \param end [in] The reference of the node the edge points to. */ - void VisitorSimpleEdge::visitEndMethodDefinition_HasKey(const structure::MethodDefinition& begin, const expression::Expression& end) { + void VisitorSimpleEdge::visitEndMethodDefinition_HasKey(const structure::MethodDefinition& begin, const base::Positioned& end) { visitAllEdgeEnd (begin, end); } /** @@ -1548,5 +1596,37 @@ namespace columbus { namespace javascript { namespace asg { void VisitorSimpleEdge::visitEndModuleSpecifier_HasLocal(const structure::ModuleSpecifier& begin, const expression::Identifier& end) { visitAllEdgeEnd (begin, end); } + /** + * \brief Edge visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitPropertyDefinition_HasKey(const structure::PropertyDefinition& begin, const base::Positioned& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndPropertyDefinition_HasKey(const structure::PropertyDefinition& begin, const base::Positioned& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitPropertyDefinition_HasValue(const structure::PropertyDefinition& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndPropertyDefinition_HasValue(const structure::PropertyDefinition& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } }}} diff --git a/lib/jsoncpp/inc/writer.h b/lib/jsoncpp/inc/writer.h index 12fd36a..9411bda 100644 --- a/lib/jsoncpp/inc/writer.h +++ b/lib/jsoncpp/inc/writer.h @@ -52,6 +52,7 @@ class JSON_API StreamWriter { stream instead.) \throw std::exception possibly, depending on configuration */ virtual int write(Value const& root, OStream* sout) = 0; + virtual int write(Value const& root, OStream* sout, const char *leftMargin) = 0; /** \brief A simple abstract factory. */ diff --git a/lib/jsoncpp/src/json_writer.cpp b/lib/jsoncpp/src/json_writer.cpp index 1d0e8e3..be5f0c7 100644 --- a/lib/jsoncpp/src/json_writer.cpp +++ b/lib/jsoncpp/src/json_writer.cpp @@ -873,6 +873,7 @@ struct BuiltStyledStreamWriter : public StreamWriter { unsigned int precision, PrecisionType precisionType); int write(Value const& root, OStream* sout) override; + int write(Value const& root, OStream* sout, const char *leftMargin) override; private: void writeValue(Value const& value); @@ -932,6 +933,22 @@ int BuiltStyledStreamWriter::write(Value const& root, OStream* sout) { sout_ = nullptr; return 0; } +int BuiltStyledStreamWriter::write(Value const& root, OStream* sout, const char *leftMargin) { + sout_ = sout; + addChildValues_ = false; + indented_ = false; + indentString_.clear(); + indentString_ = leftMargin; + writeCommentBeforeValue(root); + if (!indented_) + writeIndent(); + indented_ = true; + writeValue(root); + writeCommentAfterValueOnSameLine(root); + *sout_ << endingLineFeedSymbol_; + sout_ = nullptr; + return 0; +} void BuiltStyledStreamWriter::writeValue(Value const& value) { switch (value.type()) { case nullValue: diff --git a/lib/lim/inc/Factory.h b/lib/lim/inc/Factory.h index d10bf0b..c7bc56d 100644 --- a/lib/lim/inc/Factory.h +++ b/lib/lim/inc/Factory.h @@ -258,8 +258,8 @@ namespace columbus { namespace lim { namespace asg { const_iterator(const const_iterator& otherit) :containerIt (otherit.containerIt),fact(otherit.fact){} const_iterator& operator++() {containerIt++; while (containerIt != fact->container.end() && ((*containerIt == NULL) || fact->getIsFiltered(*containerIt))) containerIt++; return *this;} const_iterator operator++(int) {const_iterator tmp(*this); operator++(); return tmp;} - bool operator==(const const_iterator& rhs) {return containerIt==rhs.containerIt;} - bool operator!=(const const_iterator& rhs) {return containerIt!=rhs.containerIt;} + bool operator==(const const_iterator& rhs) const {return containerIt==rhs.containerIt;} + bool operator!=(const const_iterator& rhs) const {return containerIt!=rhs.containerIt;} const base::Base* operator*() {return *containerIt;} friend class Factory; }; diff --git a/lib/lim/src/ClassDiagram.cpp b/lib/lim/src/ClassDiagram.cpp index 2495265..05d4432 100644 --- a/lib/lim/src/ClassDiagram.cpp +++ b/lib/lim/src/ClassDiagram.cpp @@ -28,11 +28,6 @@ namespace columbus { namespace lim { namespace asg { -const short acdMultiplicityZero = 0; -const short acdMultiplicityOne = 1; -const short acdMultiplicityMany = 2; -const short acdMultiplicityAny = 3; - ClassDiagram::ClassDiagram(){ emptyContainer = new ListIteratorAssocContainer::Container(); } @@ -165,7 +160,7 @@ void ClassDiagram::createClassDiagram(Factory& fact) { } const std::pair ClassDiagram::resolveSimpleType(const NodeId type, const Factory& fact) { - const Factory::TurnFilterOffSafely& tfos(fact); + const Factory::TurnFilterOffSafely tfos(fact); std::pair result(0, cdtValue); if (!Common::getIsValid(type)) diff --git a/lib/limmetrics/CMakeLists.txt b/lib/limmetrics/CMakeLists.txt index ef32db0..d001b8b 100644 --- a/lib/limmetrics/CMakeLists.txt +++ b/lib/limmetrics/CMakeLists.txt @@ -7,15 +7,11 @@ set (SOURCES src/metrics/Aggregates.cpp src/metrics/CBO.cpp src/metrics/Documentation.cpp - src/metrics/Halstead.cpp src/metrics/Inheritance.cpp src/metrics/LCOM5.cpp src/metrics/LOC.cpp src/metrics/McCC.cpp - src/metrics/NA.cpp src/metrics/NCL.cpp - src/metrics/NII.cpp - src/metrics/NL.cpp src/metrics/NM.cpp src/metrics/NOI.cpp src/metrics/NOS.cpp @@ -35,15 +31,11 @@ set (SOURCES inc/metrics/Aggregates.h inc/metrics/CBO.h inc/metrics/Documentation.h - inc/metrics/Halstead.h inc/metrics/Inheritance.h inc/metrics/LCOM5.h inc/metrics/LOC.h inc/metrics/McCC.h - inc/metrics/NA.h inc/metrics/NCL.h - inc/metrics/NII.h - inc/metrics/NL.h inc/metrics/NM.h inc/metrics/NOI.h inc/metrics/NOS.h @@ -59,4 +51,3 @@ set (SOURCES add_library (${LIBNAME} STATIC ${SOURCES}) add_dependencies (${LIBNAME} lim) set_visual_studio_project_folder(${LIBNAME} FALSE) - diff --git a/lib/limmetrics/inc/LimMetrics.h b/lib/limmetrics/inc/LimMetrics.h index 06a2956..e74a6ef 100644 --- a/lib/limmetrics/inc/LimMetrics.h +++ b/lib/limmetrics/inc/LimMetrics.h @@ -26,8 +26,7 @@ #include "RulParser.h" -//#include -//#include +#include namespace columbus { namespace lim { namespace metrics { @@ -40,6 +39,7 @@ namespace columbus { namespace lim { namespace metrics { // LimMetricsVisitor( asg::Factory& factory, graph::Graph& graph, rul::RulHandler& rul, SharedContainers& shared); + LimMetricsVisitor( asg::Factory& factory, graph::Graph& graph, std::unique_ptr rulParser); virtual ~LimMetricsVisitor(); // @@ -77,7 +77,7 @@ namespace columbus { namespace lim { namespace metrics { asg::Factory& factory; ///> The lim factory graph::Graph& graph; ///> The graph converted from the above lim factory - RulParser rul; ///> The corresponding (parsed) rul file + std::unique_ptr rul; ///> The corresponding (parsed) rul file const asg::ReverseEdges& reverseEdges; ///> Reverse edges /** diff --git a/lib/limmetrics/inc/RulParser.h b/lib/limmetrics/inc/RulParser.h index 20f2c70..35b38a8 100644 --- a/lib/limmetrics/inc/RulParser.h +++ b/lib/limmetrics/inc/RulParser.h @@ -37,6 +37,10 @@ namespace columbus { namespace lim { namespace metrics { */ RulParser( rul::RulHandler& rul, SharedContainers& shared); + /** + * Parses the rules + */ + void run(); /** * Deletes the allocated MetricHandlers */ @@ -65,11 +69,6 @@ namespace columbus { namespace lim { namespace metrics { */ void parse(); - /** - * This method matches a MetricHandler instance to a given metric in the RUL by its name - */ - MetricHandler* matchHandler( const std::string& id, bool enabled ); - /** * This method sorts the loaded handlers by their dependencies so that when a * concrete node is processed they can be simply executed in order @@ -89,20 +88,32 @@ namespace columbus { namespace lim { namespace metrics { */ rul::RulHandler& rul; - /** - * Shared containers - */ - SharedContainers& shared; - /** * Common stack maintenance for the shared containers */ void stack( const NodeWrapper& node, bool push ); - + /** * Checks whether a certain metric is calculated for a specific node type */ bool isCalculatedFor( const std::string& metric, NodeWrapper& node ); + + /** + * True if the rule is already processed. + */ + bool processed; + + protected: + /** + * This method matches a MetricHandler instance to a given metric in the RUL by its name + */ + virtual MetricHandler* matchHandler( const std::string& id, bool enabled ); + + /** + * Shared containers + */ + SharedContainers& shared; + }; }}} diff --git a/lib/limmetrics/inc/metrics/Aggregates.h b/lib/limmetrics/inc/metrics/Aggregates.h index 1f533e8..3b0b813 100644 --- a/lib/limmetrics/inc/metrics/Aggregates.h +++ b/lib/limmetrics/inc/metrics/Aggregates.h @@ -61,42 +61,6 @@ namespace columbus { AvgWMC(bool enabled, SharedContainers* shared) : AvgBase("AvgWMC", "TWMC", "TNCL", enabled, shared) {} }; - // Maintainability indices - - class MIBase : public MetricHandler { - public: - MIBase(const std::string& name, bool enabled, SharedContainers* shared); - protected: - virtual double calc(double hvol, int mccc, int lloc, double cd) = 0; - }; - - class MI : public MIBase { - public: - MI(bool enabled, SharedContainers* shared) : MIBase("MI", enabled, shared) {} - protected: - double calc(double hvol, int mccc, int lloc, double cd) override; - }; - - class MISEI : public MIBase { - public: - MISEI(bool enabled, SharedContainers* shared) : MIBase("MISEI", enabled, shared) {} - protected: - double calc(double hvol, int mccc, int lloc, double cd) override; - }; - - class MIMS : public MIBase { - public: - MIMS(bool enabled, SharedContainers* shared) : MIBase("MIMS", enabled, shared) {} - protected: - double calc(double hvol, int mccc, int lloc, double cd) override; - }; - - class MISM : public MIBase { - public: - MISM(bool enabled, SharedContainers* shared) : MIBase("MISM", enabled, shared) {} - protected: - double calc(double hvol, int mccc, int lloc, double cd) override; - }; } } } diff --git a/lib/limmetrics/inc/metrics/CBO.h b/lib/limmetrics/inc/metrics/CBO.h index d52a595..ad659d7 100644 --- a/lib/limmetrics/inc/metrics/CBO.h +++ b/lib/limmetrics/inc/metrics/CBO.h @@ -30,20 +30,16 @@ namespace columbus { namespace lim { namespace metrics { CBOBase( const std::string& name, MetricDataTypes type, bool enabled, SharedContainers* shared = NULL ); protected: const std::string& translateLevel( asg::Language language, const std::string& level ) const override; - }; - - class CBO : public CBOBase { - public: - CBO( bool enabled, SharedContainers* shared ); + std::set collectUsedClasses(const asg::logical::Class& clazz) const; private: void collectUsedClasses( const asg::base::Base& to, const asg::logical::Class& node, std::set& usedClasses) const; void getClassOfType( const asg::type::Type& type, const asg::logical::Class& node, std::set& usedClasses ) const; const asg::logical::Class* getClassOfReferencedMember( const asg::logical::Class& fromClass, const asg::logical::Member& referedMember ) const; }; - class CBOI : public CBOBase { + class CBO : public CBOBase { public: - CBOI( bool enabled, SharedContainers* shared ); + CBO( bool enabled, SharedContainers* shared ); }; class TCBO : public MetricHandler { diff --git a/lib/limmetrics/inc/metrics/Documentation.h b/lib/limmetrics/inc/metrics/Documentation.h index c7babae..daca060 100644 --- a/lib/limmetrics/inc/metrics/Documentation.h +++ b/lib/limmetrics/inc/metrics/Documentation.h @@ -117,30 +117,6 @@ namespace columbus { namespace lim { namespace metrics { TAD( bool enabled, SharedContainers* shared ); }; - class CDBase : public DocBase { - public: - typedef unsigned int (asg::logical::Scope::*ScopePtr) () const; - typedef unsigned int (asg::base::Component::*ComponentPtr) () const; - - CDBase( bool total, bool enabled, SharedContainers* shared ); - protected: - const std::string& translateLevel( asg::Language language, const std::string& level ) const override; - private: - ScopePtr scopeLLOC; - ComponentPtr componentLLOC; - std::string CLOC; - }; - - class CD : public CDBase { - public: - CD( bool enabled, SharedContainers* shared ); - }; - - class TCD : public CDBase { - public: - TCD( bool enabled, SharedContainers* shared ); - }; - }}} #endif diff --git a/lib/limmetrics/inc/metrics/Halstead.h b/lib/limmetrics/inc/metrics/Halstead.h deleted file mode 100644 index 54990b8..0000000 --- a/lib/limmetrics/inc/metrics/Halstead.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * This file is part of OpenStaticAnalyzer. - * - * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged - * - * Licensed under Version 1.2 of the EUPL (the "Licence"); - * - * You may not use this work except in compliance with the Licence. - * - * You may obtain a copy of the Licence in the LICENSE file or at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ - -#ifndef _METRICS_HALSTEAD_H_ -#define _METRICS_HALSTEAD_H_ - -#include "../MetricHandler.h" - -namespace columbus { - namespace lim { - namespace metrics { - - /** - * Program Vocabulary = number of distinct operators + number of distinct operands - */ - class HPV : public MetricHandler { - public: - HPV(bool enabled, SharedContainers* shared); - }; - - /** - * Program Length = total number of operators + total number of operands - */ - class HPL : public MetricHandler { - public: - HPL(bool enabled, SharedContainers* shared); - }; - - /** - * Calculated Program Length = n1 * log2(n1) + n2 * log2(n2) - */ - class HCPL : public MetricHandler { - public: - HCPL(bool enabled, SharedContainers* shared); - }; - - /** - * Volume = PL * log1(PV) - */ - class HVOL : public MetricHandler { - public: - HVOL(bool enabled, SharedContainers* shared); - }; - - /** - * Difficulty = (n1/2) * (N2/n2) - */ - class HDIF : public MetricHandler { - public: - HDIF(bool enabled, SharedContainers* shared); - }; - - /** - * Effort = DIF * VOL - */ - class HEFF : public MetricHandler { - public: - HEFF(bool enabled, SharedContainers* shared); - }; - - /** - * Time required to program - * TRP = EFF / 18 seconds - */ - class HTRP : public MetricHandler { - public: - HTRP(bool enabled, SharedContainers* shared); - }; - - /** - * Number of Delivered Bugs - * NDB = E^(2/3)/3000 - */ - class HNDB : public MetricHandler { - public: - HNDB(bool enabled, SharedContainers* shared); - }; - - } - } -} - -#endif diff --git a/lib/limmetrics/inc/metrics/NA.h b/lib/limmetrics/inc/metrics/NA.h deleted file mode 100644 index 75eb7e7..0000000 --- a/lib/limmetrics/inc/metrics/NA.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * This file is part of OpenStaticAnalyzer. - * - * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged - * - * Licensed under Version 1.2 of the EUPL (the "Licence"); - * - * You may not use this work except in compliance with the Licence. - * - * You may obtain a copy of the Licence in the LICENSE file or at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ - -#ifndef _METRICS_NA_H_ -#define _METRICS_NA_H_ - -#include "../MetricHandler.h" - -namespace columbus { namespace lim { namespace metrics { - - class NABase : public MetricHandler { - - public: - NABase( const std::string& name, bool local, bool total, bool enabled, SharedContainers* shared ); - - protected: - void traverseClass( NodeWrapper& node ); - void processAttribute( const asg::logical::Attribute& attr, bool local ); - void add( const asg::logical::Attribute& attr, Info& info, bool local ); - void innerAdd( const asg::logical::Attribute& attr, Info& info, bool local, std::string normalName, std::string localName ); - const std::string& translateLevel( asg::Language language, const std::string& level ) const override; - - bool localMetric; - bool totalMetric; - }; - - class NA : public NABase { - public: - NA( bool enabled, SharedContainers* shared ) : NABase( "NA", false, false, enabled, shared ) {} - }; - - class NLA : public NABase { - public: - NLA( bool enabled, SharedContainers* shared ) : NABase( "NLA", true, false, enabled, shared ) {} - }; - - class NPA : public NABase { - public: - NPA( bool enabled, SharedContainers* shared ) : NABase( "NPA", false, false, enabled, shared ) {} - }; - - class NLPA : public NABase { - public: - NLPA( bool enabled, SharedContainers* shared ) : NABase( "NLPA", true, false, enabled, shared ) {} - }; - - class TNA : public NABase { - public: - TNA( bool enabled, SharedContainers* shared ) : NABase( "TNA", false, true, enabled, shared ) {} - }; - - class TNLA : public NABase { - public: - TNLA( bool enabled, SharedContainers* shared ) : NABase( "TNLA", true, true, enabled, shared ) {} - }; - - class TNPA : public NABase { - public: - TNPA( bool enabled, SharedContainers* shared ) : NABase( "TNPA", false, true, enabled, shared ) {} - }; - - class TNLPA : public NABase { - public: - TNLPA( bool enabled, SharedContainers* shared ) : NABase( "TNLPA", true, true, enabled, shared ) {} - }; - -}}} - -#endif diff --git a/lib/limmetrics/inc/metrics/NL.h b/lib/limmetrics/inc/metrics/NL.h deleted file mode 100644 index 8653896..0000000 --- a/lib/limmetrics/inc/metrics/NL.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is part of OpenStaticAnalyzer. - * - * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged - * - * Licensed under Version 1.2 of the EUPL (the "Licence"); - * - * You may not use this work except in compliance with the Licence. - * - * You may obtain a copy of the Licence in the LICENSE file or at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ - -#ifndef _METRICS_NL_H_ -#define _METRICS_NL_H_ - -#include "../MetricHandler.h" - -namespace columbus { namespace lim { namespace metrics { - - class NLBase : public MetricHandler { - - public: - NLBase( const std::string& name, MetricDataTypes type, bool enabled ); - - protected: - virtual int getValue( const asg::logical::Method& method ) = 0; - const std::string& translateLevel( asg::Language language, const std::string& level ) const override; - }; - - class NL : public NLBase { - - public: - NL( bool enabled ); - - protected: - virtual int getValue( const asg::logical::Method& method ); - }; - - class NLE : public NLBase { - - public: - NLE( bool enabled ); - - protected: - virtual int getValue( const asg::logical::Method& method ); - }; - -}}} - -#endif diff --git a/lib/limmetrics/src/LimMetrics.cpp b/lib/limmetrics/src/LimMetrics.cpp index edc0133..814435a 100644 --- a/lib/limmetrics/src/LimMetrics.cpp +++ b/lib/limmetrics/src/LimMetrics.cpp @@ -46,7 +46,20 @@ namespace columbus { namespace lim { namespace metrics { LimMetricsVisitor::LimMetricsVisitor( Factory& factory, graph::Graph& graph, rul::RulHandler& rul, SharedContainers& shared) : factory( factory ), graph( graph ), - rul( RulParser( rul, shared) ), + rul( make_unique( rul, shared ) ), + reverseEdges( factory.getReverseEdges() ), + phase( phaseVisit ), + useVisitEnd( true ) + { + ap.setVisitSpecialNodes(true, true); + ap.setCrossEdgeToTraversal(lim::asg::edkScope_HasMember); + ap.setSafeMode(); + } + + LimMetricsVisitor::LimMetricsVisitor( Factory& factory, graph::Graph& graph, std::unique_ptr rulParser) : + factory( factory ), + graph( graph ), + rul( move(rulParser) ), reverseEdges( factory.getReverseEdges() ), phase( phaseVisit ), useVisitEnd( true ) @@ -63,15 +76,15 @@ namespace columbus { namespace lim { namespace metrics { // void LimMetricsVisitor::run() { - + rul->run(); // main run WriteMsg::write( CMSG_LIMMETRICS_PHASE, "Visit" ); apRun(); WriteMsg::write( CMSG_LIMMETRICS_PHASE_OVER, "Visit" ); - rul.phaseOver( phaseVisit ); + rul->phaseOver( phaseVisit ); WriteMsg::write( CMSG_LIMMETRICS_PHASE_OVER, "VisitEnd" ); - rul.phaseOver( phaseVisitEnd ); + rul->phaseOver( phaseVisitEnd ); // finalization before totaling phase = phaseFinishVisit; @@ -79,14 +92,14 @@ namespace columbus { namespace lim { namespace metrics { WriteMsg::write( CMSG_LIMMETRICS_PHASE, "FinishVisit" ); apRun(); WriteMsg::write( CMSG_LIMMETRICS_PHASE_OVER, "FinishVisit" ); - rul.phaseOver( phaseFinishVisit ); + rul->phaseOver( phaseFinishVisit ); // finalization AFTER totaling phase = phaseFinalize; WriteMsg::write( CMSG_LIMMETRICS_PHASE, "Finalize" ); apRun(); WriteMsg::write( CMSG_LIMMETRICS_PHASE_OVER, "Finalize" ); - rul.phaseOver( phaseFinalize ); + rul->phaseOver( phaseFinalize ); } @@ -143,14 +156,14 @@ namespace columbus { namespace lim { namespace metrics { void LimMetricsVisitor::begin( const base::Base& node ) { VISIT_DEBUG( "begin" ); NodeWrapper nw( node, graph ); - rul.dispatch( phase, nw ); + rul->dispatch( phase, nw ); } void LimMetricsVisitor::end( const base::Base& node ) { if ( useVisitEnd ) { VISIT_DEBUG( "end" ); NodeWrapper nw( node, graph ); - rul.dispatch( phaseVisitEnd, nw ); + rul->dispatch( phaseVisitEnd, nw ); } } diff --git a/lib/limmetrics/src/MetricHandler.cpp b/lib/limmetrics/src/MetricHandler.cpp index 9208809..2776cf9 100644 --- a/lib/limmetrics/src/MetricHandler.cpp +++ b/lib/limmetrics/src/MetricHandler.cpp @@ -324,7 +324,7 @@ namespace columbus { namespace lim { namespace metrics { if ( shared ) { const base::Base& base = node.getLimNode(); - Info* info; + Info* info = nullptr; if ( Common::getIsScope( base ) ) { info = & shared->scopes.map[&base]; diff --git a/lib/limmetrics/src/RulParser.cpp b/lib/limmetrics/src/RulParser.cpp index ac93468..5e9db52 100644 --- a/lib/limmetrics/src/RulParser.cpp +++ b/lib/limmetrics/src/RulParser.cpp @@ -28,10 +28,7 @@ #include "../inc/metrics/LCOM5.h" #include "../inc/metrics/LOC.h" #include "../inc/metrics/McCC.h" -#include "../inc/metrics/NA.h" #include "../inc/metrics/NCL.h" -#include "../inc/metrics/NII.h" -#include "../inc/metrics/NL.h" #include "../inc/metrics/NM.h" #include "../inc/metrics/NOI.h" #include "../inc/metrics/NOS.h" @@ -40,7 +37,6 @@ #include "../inc/metrics/RFC.h" #include "../inc/metrics/TNFI.h" #include "../inc/metrics/WMC.h" -#include "../inc/metrics/Halstead.h" #include "../inc/metrics/Aggregates.h" @@ -54,9 +50,17 @@ using namespace columbus::lim::asg; namespace columbus { namespace lim { namespace metrics { - RulParser::RulParser( RulHandler& rul, SharedContainers& shared) : rul( rul ), shared( shared ) { - parse(); - sort(); + RulParser::RulParser( RulHandler& rul, SharedContainers& shared) : rul( rul ), processed(false), shared( shared ) { + } + + void RulParser::run() + { + if (!processed) + { + parse(); + sort(); + processed = true; + } } RulParser::~RulParser() { @@ -70,19 +74,19 @@ namespace columbus { namespace lim { namespace metrics { void RulParser::parse() { deque queue; - set groupIds; + set groupIds; rul.getGroupIdList( groupIds ); // loading all metrics - set::iterator groupIt = groupIds.begin(), groupEnd = groupIds.end(); + set::iterator groupIt = groupIds.begin(), groupEnd = groupIds.end(); for ( ; groupIt != groupEnd; ++groupIt ) { string groupId = *groupIt; - set ids; + set ids; rul.getGroupMembers( groupId, ids ); - set::iterator metricsIt = ids.begin(), metricsEnd = ids.end(); + set::iterator metricsIt = ids.begin(), metricsEnd = ids.end(); for ( ; metricsIt != metricsEnd; ++metricsIt ) { string id = *metricsIt; @@ -116,103 +120,65 @@ namespace columbus { namespace lim { namespace metrics { MetricHandler* RulParser::matchHandler( const string& id, bool enabled ) { + // Documentation.h + MATCH_SHARED( DLOC ) + MATCH_SHARED( PDA ) + MATCH_SHARED( TPDA ) + MATCH_SHARED( PUA ) + MATCH_SHARED( TPUA ) + MATCH_SHARED( AD ) + MATCH_SHARED( TAD ) + + // Inheritance.h + MATCH_SHARED( NOP ) + MATCH_SHARED( NOA ) + MATCH_SHARED( NOD ) - // CBO.h - MATCH_SHARED( CBOI ) + // NCL.h + MATCH_SHARED( NIN ) + MATCH_SHARED( NST ) + MATCH_SHARED( NUN ) + MATCH_SHARED( TNIN ) + MATCH_SHARED( TNST ) + MATCH_SHARED( TNUN ) + MATCH_SHARED( TNPCL ) + MATCH_SHARED( TNPIN ) + MATCH_SHARED( TNPEN ) + MATCH_SHARED( TNPST ) + MATCH_SHARED( TNPUN ) - // Documentation.h - MATCH_SHARED( DLOC ) - MATCH_SHARED( PDA ) - MATCH_SHARED( TPDA ) - MATCH_SHARED( PUA ) - MATCH_SHARED( TPUA ) - MATCH_SHARED( AD ) - MATCH_SHARED( TAD ) - MATCH_SHARED( CD ) - MATCH_SHARED( TCD ) - - // Halstead.h - MATCH_SHARED( HCPL ) - MATCH_SHARED( HVOL ) - MATCH_SHARED( HDIF ) - MATCH_SHARED( HEFF ) - MATCH_SHARED( HTRP ) - MATCH_SHARED( HNDB ) - - // Inheritance.h - MATCH_SHARED( NOP ) - MATCH_SHARED( NOA ) - MATCH_SHARED( NOD ) - - // NA.h - MATCH_SHARED( NA ); - MATCH_SHARED( NLA ); - MATCH_SHARED( NPA ); - MATCH_SHARED( NLPA ); - MATCH_SHARED( TNA ); - MATCH_SHARED( TNLA ); - MATCH_SHARED( TNPA ); - MATCH_SHARED( TNLPA ); + // NM.h + MATCH_SHARED( NM ) + MATCH_SHARED( NLM ) + MATCH_SHARED( NG ) + MATCH_SHARED( NLG ) + MATCH_SHARED( NS ) + MATCH_SHARED( NLS ) + MATCH_SHARED( NPM ) + MATCH_SHARED( NLPM ) + MATCH_SHARED( TNM ) + MATCH_SHARED( TNLM ) + MATCH_SHARED( TNLG ) + MATCH_SHARED( TNLS ) + MATCH_SHARED( TNPM ) + MATCH_SHARED( TNLPM ) + + + // NOS.h + MATCH_SHARED( NOS ) + MATCH_SHARED( TNOS ) - // NCL.h - MATCH_SHARED( NIN ) - MATCH_SHARED( NST ) - MATCH_SHARED( NUN ) - MATCH_SHARED( TNIN ) - MATCH_SHARED( TNST ) - MATCH_SHARED( TNUN ) - MATCH_SHARED( TNPCL ) - MATCH_SHARED( TNPIN ) - MATCH_SHARED( TNPEN ) - MATCH_SHARED( TNPST ) - MATCH_SHARED( TNPUN ) - - // NII.h - MATCH_SHARED( NII ) - - // NL.h - MATCH( NL ) - MATCH( NLE ) - - // NM.h - MATCH_SHARED( NM ) - MATCH_SHARED( NLM ) - MATCH_SHARED( NG ) - MATCH_SHARED( NLG ) - MATCH_SHARED( NS ) - MATCH_SHARED( NLS ) - MATCH_SHARED( NPM ) - MATCH_SHARED( NLPM ) - MATCH_SHARED( TNM ) - MATCH_SHARED( TNLM ) - MATCH_SHARED( TNLG ) - MATCH_SHARED( TNLS ) - MATCH_SHARED( TNPM ) - MATCH_SHARED( TNLPM ) - - - // NOS.h - MATCH_SHARED( NOS ) - MATCH_SHARED( TNOS ) - - // NPKG.h - MATCH_SHARED( NPKG ) - MATCH_SHARED( TNPKG ) - - // NUMPAR.h - MATCH( NUMPAR ) - - - // TNFI.h - MATCH_SHARED( TNFI ) - MATCH_SHARED( TNDI ) - - // Aggregates.h - MATCH_SHARED( MI ) - MATCH_SHARED( MISEI ) - MATCH_SHARED( MIMS ) - MATCH_SHARED( MISM ) + // NPKG.h + MATCH_SHARED( NPKG ) + MATCH_SHARED( TNPKG ) + + // NUMPAR.h + MATCH( NUMPAR ) + + // TNFI.h + MATCH_SHARED( TNFI ) + MATCH_SHARED( TNDI ) // WMC.h MATCH_SHARED( WMC ) @@ -222,9 +188,6 @@ namespace columbus { namespace lim { namespace metrics { MATCH_SHARED( TLCOM5 ) // McCC.h MATCH_SHARED( McCC ) - // Halstead.h - MATCH_SHARED( HPV ) - MATCH_SHARED( HPL ) // CBO.h MATCH_SHARED( CBO ) MATCH_SHARED( TCBO ) diff --git a/lib/limmetrics/src/metrics/Aggregates.cpp b/lib/limmetrics/src/metrics/Aggregates.cpp index 7df009c..7277537 100644 --- a/lib/limmetrics/src/metrics/Aggregates.cpp +++ b/lib/limmetrics/src/metrics/Aggregates.cpp @@ -69,50 +69,6 @@ namespace columbus { if (info.maps.find(name) != info.maps.end()) return info.mapCount(name); return 0; } - - MIBase::MIBase(const std::string& name, bool enabled, SharedContainers* shared) : MetricHandler(name, mdtFloat, enabled, shared) - { - dependencies.insert("HVOL"); - dependencies.insert("McCC"); - dependencies.insert("LLOC"); - dependencies.insert("CD"); - - this->registerHandler(phaseVisitEnd, NTYPE_LIM_METHOD, limLangOther, false, [this](NodeWrapper& node) { - - double hvol = node.getFloatMetric("HVOL"); - int mccc = node.getIntMetric("McCC"); - int lloc = node.getIntMetric("LLOC"); - double cd = node.getFloatMetric("CD"); - - double mi = 0; - if (hvol > 0 && lloc > 0) { - mi = this->calc(hvol, mccc, lloc, cd); - } - - addMetric(node, mi); - - }); - } - - double MI::calc(double hvol, int mccc, int lloc, double cd) - { - return 171 - 5.2 * log(hvol) - 0.23 * mccc - 16.2 * log(lloc); - } - - double MISEI::calc(double hvol, int mccc, int lloc, double cd) - { - return 171 - 5.2 * log2(hvol) - 0.23 * mccc - 16.2 * log2(lloc) + 50 * sin(sqrt(2.4 * cd)); - } - - double MIMS::calc(double hvol, int mccc, int lloc, double cd) - { - return max(.0, (171 - 5.2 * log(hvol) - 0.23 * mccc - 16.2 * log(lloc)) * 100 / 171); - } - - double MISM::calc(double hvol, int mccc, int lloc, double cd) - { - return max(.0, (171 - 5.2 * log2(hvol) - 0.23 * mccc - 16.2 * log2(lloc) + 50 * sin(sqrt(2.4 * cd))) * 100 / 171); - } } } } diff --git a/lib/limmetrics/src/metrics/CBO.cpp b/lib/limmetrics/src/metrics/CBO.cpp index 169b53d..78f7dc9 100644 --- a/lib/limmetrics/src/metrics/CBO.cpp +++ b/lib/limmetrics/src/metrics/CBO.cpp @@ -68,6 +68,22 @@ namespace columbus { namespace lim { namespace metrics { this->registerHandler( phaseVisit, NTYPE_LIM_CLASS, limLangOther, false, [this]( NodeWrapper& node ) { const logical::Class& clazz = node.getLimNode(); + set cbo = collectUsedClasses(clazz); + + int cboNum = (int)cbo.size(); + addMetric( node, cboNum ); + + // propagate to package level + this->shared->currentPackageInfo().ints[this->name] += cboNum; + + cleanup( node ); + + }); + + } + + std::set CBOBase::collectUsedClasses(const logical::Class& clazz) const + { set cbo; ListIterator memberIt = clazz.getMemberListIteratorBegin(), memberEnd = clazz.getMemberListIteratorEnd(); @@ -158,26 +174,10 @@ namespace columbus { namespace lim { namespace metrics { collectUsedClasses( dynamic_cast( *parentIt ), clazz, cbo ); } - // Inverse CBO handling - set::iterator cboIt = cbo.begin(), cboEnd = cbo.end(); - for ( ; cboIt != cboEnd; ++cboIt ) { - Info& info = this->shared->scopes.map[ *cboIt ]; - info.sets["CBOI"].insert( clazz.getId() ); - } - - int cboNum = (int)cbo.size(); - addMetric( node, cboNum ); - - // propagate to package level - this->shared->currentPackageInfo().ints[this->name] += cboNum; - - cleanup( node ); - - }); - + return cbo; } - void CBO::collectUsedClasses( const asg::base::Base& to, const asg::logical::Class& node, std::set& usedClasses) const { + void CBOBase::collectUsedClasses( const asg::base::Base& to, const asg::logical::Class& node, std::set& usedClasses) const { if ( Common::getIsMethodCall( to ) ) { const logical::MethodCall& toMethodCall = (const logical::MethodCall&)to; @@ -216,7 +216,7 @@ namespace columbus { namespace lim { namespace metrics { } } - void CBO::getClassOfType( const asg::type::Type& type, const asg::logical::Class& node, std::set& usedClasses ) const { + void CBOBase::getClassOfType( const asg::type::Type& type, const asg::logical::Class& node, std::set& usedClasses ) const { ListIterator typeFormerIt = type.getTypeFormerListIteratorBegin(), typeFormerEnd = type.getTypeFormerListIteratorEnd(); for ( ; typeFormerIt != typeFormerEnd; ++typeFormerIt ) { @@ -294,7 +294,7 @@ namespace columbus { namespace lim { namespace metrics { } } - const logical::Class* CBO::getClassOfReferencedMember( const logical::Class& fromClass, const logical::Member& referedMember ) const { + const logical::Class* CBOBase::getClassOfReferencedMember( const logical::Class& fromClass, const logical::Member& referedMember ) const { unsigned int sameComponentCounter = 0; ListIterator it = this->shared->factory->getReverseEdges().constIteratorBegin( referedMember.getId(), edkScope_HasMember ); @@ -318,22 +318,6 @@ namespace columbus { namespace lim { namespace metrics { return NULL; } - CBOI::CBOI( bool enabled, SharedContainers* shared ) : CBOBase( "CBOI", mdtInt, enabled, shared ) { - - dependencies.insert( "CBO" ); - - this->registerHandler( phaseFinishVisit, NTYPE_LIM_CLASS, limLangOther, false, [this]( NodeWrapper& node ) { - - const logical::Class& clazz = node.getLimNode(); - Info& info = this->shared->scopes.map[ &clazz ]; - addMetric( node, (int) info.sets[this->name].size() ); - - cleanup( node ); - - }); - - } - TCBO::TCBO(bool enabled, SharedContainers* shared) : MetricHandler("TCBO", mdtInt, enabled, shared) { dependencies.insert("CBO"); propagateScopeInt(phaseFinalize, NTYPE_LIM_PACKAGE, limLangOther); diff --git a/lib/limmetrics/src/metrics/Documentation.cpp b/lib/limmetrics/src/metrics/Documentation.cpp index a882f3c..4678066 100644 --- a/lib/limmetrics/src/metrics/Documentation.cpp +++ b/lib/limmetrics/src/metrics/Documentation.cpp @@ -648,71 +648,5 @@ namespace columbus { namespace lim { namespace metrics { AD::AD( bool enabled, SharedContainers* shared ) : ADBase( false, enabled, shared ) {} TAD::TAD( bool enabled, SharedContainers* shared ) : ADBase( true, enabled, shared ) {} - - // - // (T)CD - // - - CDBase::CDBase( bool total, bool enabled, SharedContainers* shared ) : DocBase( (total ? "TCD" : "CD"), mdtFloat, enabled, shared ) { - - if ( total ) { - dependencies.insert( "TLLOC" ); - dependencies.insert( "TCLOC" ); - scopeLLOC = &logical::Scope::getTLLOC; - componentLLOC = &base::Component::getTLLOC; - CLOC = "TCLOC"; - } else { - dependencies.insert( "LLOC" ); - dependencies.insert( "CLOC" ); - scopeLLOC = &logical::Scope::getLLOC; - CLOC = "CLOC"; - } - - registerHandler( ( total ? phaseFinalize : phaseVisitEnd ), NTYPE_LIM_METHOD, limLangOther, false, [this] ( NodeWrapper& node ) { - - const logical::Scope& scope = node.getLimNode(); - - int c = this->shared->scopes.map[&scope].ints[this->CLOC]; - int l = (scope.*(this->scopeLLOC))(); - - int denom = c + l; - double cd = ( denom == 0 ) ? 0.0 : ( c / (double)denom ); - - addMetric( node, cd ); - - }); - - if ( total ) { - - registerHandler( phaseFinalize, NTYPE_LIM_COMPONENT, limLangOther, false, [this] ( NodeWrapper& node ) { - - const base::Component& component = node.getLimNode(); - - int c = this->shared->components.map[&component].ints[this->CLOC]; - int l = (component.*(this->componentLLOC))(); - - int denom = c + l; - double cd = ( denom == 0 ) ? 0.0 : ( c / (double)denom ); - - addMetric( node, cd ); - - }); - - } - } - - const string& CDBase::translateLevel( Language language, const string& level ) const { - - const string& newLevel = DocBase::translateLevel( language, level ); - - if ( newLevel == NTYPE_LIM_CLASS || newLevel == NTYPE_LIM_PACKAGE ) { - return NTYPE_LIM_METHOD; - } - - return newLevel; - } - - CD::CD( bool enabled, SharedContainers* shared ) : CDBase( false, enabled, shared ) {} - TCD::TCD( bool enabled, SharedContainers* shared ) : CDBase( true, enabled, shared ) {} - + }}} diff --git a/lib/limmetrics/src/metrics/Halstead.cpp b/lib/limmetrics/src/metrics/Halstead.cpp deleted file mode 100644 index 0b8551f..0000000 --- a/lib/limmetrics/src/metrics/Halstead.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/* - * This file is part of OpenStaticAnalyzer. - * - * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged - * - * Licensed under Version 1.2 of the EUPL (the "Licence"); - * - * You may not use this work except in compliance with the Licence. - * - * You may obtain a copy of the Licence in the LICENSE file or at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ - -#include "../../inc/metrics/Halstead.h" - -using namespace std; -using namespace columbus::lim::asg; -using namespace columbus::graphsupport::graphconstants; - -namespace columbus { - namespace lim { - namespace metrics { - - HPV::HPV(bool enabled, SharedContainers* shared) : MetricHandler("HPV", mdtInt, enabled, shared) { - - this->registerHandler(phaseVisit, NTYPE_LIM_METHOD, limLangOther, false, [this](NodeWrapper& node) { - - const logical::Method& method = node.getLimNode(); - - // propagate the Sum of Distinct Operators and Operands attribute from the LIM - addMetric(node, (int)method.getDistinctOperands() + (int)method.getDistinctOperators()); - - }); - - } - - - - HPL::HPL(bool enabled, SharedContainers* shared) : MetricHandler("HPL", mdtInt, enabled, shared) { - - this->registerHandler(phaseVisit, NTYPE_LIM_METHOD, limLangOther, false, [this](NodeWrapper& node) { - - const logical::Method& method = node.getLimNode(); - - // propagate the Sum of Total Operators and Total Operands attribute from the LIM - addMetric(node, (int)method.getTotalOperands() + (int)method.getTotalOperators()); - }); - } - - HCPL::HCPL(bool enabled, SharedContainers* shared) : MetricHandler("HCPL", mdtFloat, enabled, shared) { - - this->registerHandler(phaseVisit, NTYPE_LIM_METHOD, limLangOther, false, [this](NodeWrapper& node) { - - const logical::Method& method = node.getLimNode(); - - // calculate calculated program length and add metric - double n1 = method.getDistinctOperators(); - double n2 = method.getDistinctOperands(); - double cpl = (n1 * log2(n1)) + (n2 * log2(n2)); - addMetric(node, cpl); - - }); - - } - - HVOL::HVOL(bool enabled, SharedContainers* shared) : MetricHandler("HVOL", mdtFloat, enabled, shared) { - - this->registerHandler(phaseVisit, NTYPE_LIM_METHOD, limLangOther, false, [this](NodeWrapper& node) { - - const logical::Method& method = node.getLimNode(); - - unsigned n = method.getDistinctOperators() + method.getDistinctOperands(); - unsigned N = method.getTotalOperators() + method.getTotalOperands(); - - double vol = N * log2(n); - addMetric(node, vol); - - }); - } - - HDIF::HDIF(bool enabled, SharedContainers* shared) : MetricHandler("HDIF", mdtFloat, enabled, shared) { - - this->registerHandler(phaseVisit, NTYPE_LIM_METHOD, limLangOther, false, [this](NodeWrapper& node) { - - const logical::Method& method = node.getLimNode(); - - unsigned n1 = method.getDistinctOperators(); - unsigned n2 = method.getDistinctOperands(); - unsigned N2 = method.getTotalOperands(); - - //null check - if (n2 == 0) { - n2 = 1; - } - - double difficulty = (n1 / 2.0) * ((double)N2 / n2); - addMetric(node, difficulty); - }); - } - - HEFF::HEFF(bool enabled, SharedContainers* shared) : MetricHandler("HEFF", mdtFloat, enabled, shared) { - - this->registerHandler(phaseVisit, NTYPE_LIM_METHOD, limLangOther, false, [this](NodeWrapper& node) { - - const logical::Method& method = node.getLimNode(); - - unsigned n1 = method.getDistinctOperators(); - unsigned n2 = method.getDistinctOperands(); - unsigned N1 = method.getTotalOperators(); - unsigned N2 = method.getTotalOperands(); - - unsigned n = n1 + n2; - unsigned N = N1 + N2; - - double vol = N * log2(n); - - //null check - if (n2 == 0) { - n2 = 1; - } - - double difficulty = (n1 / 2.0) * ((double)N2 / n2); - double effort = difficulty * vol; - - addMetric(node, effort); - }); - } - - HTRP::HTRP(bool enabled, SharedContainers* shared) : MetricHandler("HTRP", mdtFloat, enabled, shared) { - - this->registerHandler(phaseVisit, NTYPE_LIM_METHOD, limLangOther, false, [this](NodeWrapper& node) { - - const logical::Method& method = node.getLimNode(); - - unsigned n1 = method.getDistinctOperators(); - unsigned n2 = method.getDistinctOperands(); - unsigned N1 = method.getTotalOperators(); - unsigned N2 = method.getTotalOperands(); - - unsigned n = n1 + n2; - unsigned N = N1 + N2; - - double vol = N * log2(n); - //null check - if (n2 == 0) { - n2 = 1; - } - double difficulty = (n1 / 2.0) * ((double)N2 / n2); - double effort = difficulty * vol; - double trp = effort / 18; - - addMetric(node, trp); - }); - } - - HNDB::HNDB(bool enabled, SharedContainers* shared) : MetricHandler("HNDB", mdtFloat, enabled, shared) { - - this->registerHandler(phaseVisit, NTYPE_LIM_METHOD, limLangOther, false, [this](NodeWrapper& node) { - - const logical::Method& method = node.getLimNode(); - - unsigned n1 = method.getDistinctOperators(); - unsigned n2 = method.getDistinctOperands(); - unsigned N1 = method.getTotalOperators(); - unsigned N2 = method.getTotalOperands(); - - unsigned n = n1 + n2; - unsigned N = N1 + N2; - - double vol = N * log2(n); - //null check - if (n2 == 0) { - n2 = 1; - } - double difficulty = (n1 / 2.0) * ((double)N2 / n2); - double effort = difficulty * vol; - double ndb = pow(effort, (float)2/3); - - addMetric(node, ndb); - }); - } - - } - } -} diff --git a/lib/limmetrics/src/metrics/NA.cpp b/lib/limmetrics/src/metrics/NA.cpp deleted file mode 100644 index 83cb460..0000000 --- a/lib/limmetrics/src/metrics/NA.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/* - * This file is part of OpenStaticAnalyzer. - * - * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged - * - * Licensed under Version 1.2 of the EUPL (the "Licence"); - * - * You may not use this work except in compliance with the Licence. - * - * You may obtain a copy of the Licence in the LICENSE file or at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ - -#include "../../inc/metrics/NA.h" - -using namespace std; -using namespace columbus::lim::asg; -using namespace columbus::graphsupport::graphconstants; - -namespace columbus { namespace lim { namespace metrics { - - // - // COMMON STUFF - // - - NABase::NABase( const string& name, bool local, bool total, bool enabled, SharedContainers* shared ) - : MetricHandler( name, mdtInt, enabled, shared ), localMetric( local ), totalMetric( total ) - { - // setting invalid values where there would be differences between C++ and C structs/unions - set common_invalids = {"NPA", "TNPA"}; - if (common_invalids.find(name) != common_invalids.end()) { - registerHandler( phaseVisit, NTYPE_LIM_STRUCTURE, limLangC, false, [this] ( NodeWrapper& node ) { - setInvalid( node ); - }); - registerHandler( phaseVisit, NTYPE_LIM_UNION, limLangC, false, [this] ( NodeWrapper& node ) { - setInvalid( node ); - }); - } - set struct_invalids = {"NLA", "NLPA", "TNLA", "TNLPA"}; - if (struct_invalids.find(name) != struct_invalids.end()) { - registerHandler( phaseVisit, NTYPE_LIM_STRUCTURE, limLangC, false, [this] ( NodeWrapper& node ) { - setInvalid( node ); - }); - } - - if ( name == "NA" ) { - - registerHandler( phaseVisit, NTYPE_LIM_CLASS, limLangOther, false, [this] ( NodeWrapper& node ) { - traverseClass( node ); - addMetric( node, (int) this->shared->currentClassInfo().sets[this->name].size() ); - }); - - propagateScopeSet( phaseVisitEnd, NTYPE_LIM_PACKAGE, limLangOther ); - - } else { - - dependencies.insert( "NA" ); - - if ( total ) { - propagateScopeSet( phaseFinalize, NTYPE_LIM_CLASS, limLangOther ); - if ( ! local ) { - propagateScopeSet( phaseFinalize, NTYPE_LIM_PACKAGE, limLangOther ); - propagateComponentSet(); - } - } else { // not total - propagateScopeSet( phaseVisitEnd, NTYPE_LIM_CLASS, limLangOther ); - if ( ! local ) { - propagateScopeSet( phaseVisitEnd, NTYPE_LIM_PACKAGE, limLangOther ); - } - } - - } - } - - void NABase::traverseClass( NodeWrapper& node ) { - - const logical::Class& clazz = node.getLimNode(); - - // local methods - ListIterator i = clazz.getMemberListIteratorBegin(), end = clazz.getMemberListIteratorEnd(); - for ( ; i != end; ++i ) { - if ( Common::getIsAttribute( *i ) ) { - const logical::Attribute& attr = dynamic_cast( *i ); - if ( !attr.getDeclares() && !attr.getIsContainedInIsEmpty() ) { - processAttribute( attr, true ); - } - } - } - - // inherited methods - set ancestors; - shared->inheritance->collectAncestors( clazz, ancestors ); - - set::iterator aIt = ancestors.begin(), aEnd = ancestors.end(); - for ( ; aIt != aEnd; ++aIt ) { - - const logical::Class& aClass = *dynamic_cast( *aIt ); - - ListIterator i = aClass.getMemberListIteratorBegin(), end = aClass.getMemberListIteratorEnd(); - for ( ; i != end; ++i ) { - if ( Common::getIsAttribute( *i ) ) { - const logical::Attribute& attr = dynamic_cast( *i ); - if ( !attr.getDeclares() && !attr.getIsContainedInIsEmpty() ) { - processAttribute( attr, false ); - } - } - } - } - - } - - void NABase::processAttribute( const asg::logical::Attribute& attr, bool local ) { - - // class level NA - add( attr, shared->currentClassInfo(), local ); - - // package level NA - if ( local ) { - add( attr, shared->currentPackageInfo(), false ); - } - - // component level NA - ListIterator i = attr.getBelongsToListIteratorBegin(), end = attr.getBelongsToListIteratorEnd(); - for ( ; i != end; ++i ) { - const base::Component& c = dynamic_cast( *i ); - Info& cInfo = shared->components.map[&c]; - add( attr, cInfo, false ); - } - } - - void NABase::add( const asg::logical::Attribute& attr, Info& info, bool local ) { - - innerAdd( attr, info, local, "NA", "NLA" ); - - if ( attr.getAccessibility() == ackPublic ) - { - innerAdd( attr, info, local, "NPA", "NLPA" ); - } - } - - void NABase::innerAdd( const asg::logical::Attribute& attr, Info& info, bool local, string normalName, string localName ) { - info.sets[normalName].insert( attr.getId() ); - if ( local ) { - info.sets[localName].insert( attr.getId() ); - } - } - - - const string& NABase::translateLevel( Language language, const string& level ) const { - const string& newLevel = MetricHandler::translateLevel( language, level ); - - // C - if ( language == limLangC ) { - // Struct/Union - if ( - ( name == "NA" || name == "TNA" ) && - ( newLevel == NTYPE_LIM_STRUCTURE || newLevel == NTYPE_LIM_UNION ) - ) { - return NTYPE_LIM_CLASS; - } - - // Enum - if ( newLevel == NTYPE_LIM_ENUM ) { - return NTYPE_LIM_CLASS; - } - } - - // C++ - // Classes/Structs are merged with Interfaces (and Unions for non-local metrics) (and Enums) - if ( language == limLangCpp ) { - if ( - newLevel == NTYPE_LIM_CLASS || - newLevel == NTYPE_LIM_INTERFACE || - ( ! localMetric && newLevel == NTYPE_LIM_UNION ) || - ( newLevel == NTYPE_LIM_ENUM ) - ) { - return NTYPE_LIM_CLASS; - } - } - - // C# - // Classes/Structs are merged with Interfaces and Enums - if ( language == limLangCsharp ) { - if ( - newLevel == NTYPE_LIM_CLASS || - newLevel == NTYPE_LIM_INTERFACE || - ( name == "NA" && newLevel == NTYPE_LIM_ENUM ) - ) { - return NTYPE_LIM_CLASS; - } - } - - return newLevel; - } - -}}} diff --git a/lib/limmetrics/src/metrics/NII.cpp b/lib/limmetrics/src/metrics/NII.cpp deleted file mode 100644 index d346455..0000000 --- a/lib/limmetrics/src/metrics/NII.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/* - * This file is part of OpenStaticAnalyzer. - * - * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged - * - * Licensed under Version 1.2 of the EUPL (the "Licence"); - * - * You may not use this work except in compliance with the Licence. - * - * You may obtain a copy of the Licence in the LICENSE file or at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ - -#include "../../inc/metrics/NII.h" - -using namespace std; -using namespace columbus::lim::asg; -using namespace columbus::graphsupport::graphconstants; - -namespace columbus { namespace lim { namespace metrics { - - NII::NII( bool enabled, SharedContainers* shared ) : MetricHandler( "NII", mdtInt, enabled, shared ) { - - // Method level NII - this->registerHandler( phaseVisit, NTYPE_LIM_METHOD, limLangOther, false, [this]( NodeWrapper& node ) { - - const logical::Method& method = node.getLimNode(); - set s; - - fillIncomingMethodInvocations( method, s, false ); - - // remove self reference - s.erase( method.getId() ); - - addMetric( node, (int) s.size() ); - - // add to class level NII - if ( ! node.isFunction() ) { - this->shared->currentClassInfo().sets[this->name].insert( s.begin(), s.end() ); - } - }); - - // Class level NII - this->registerHandler( phaseVisitEnd, NTYPE_LIM_CLASS, limLangOther, false, [this]( NodeWrapper& node ) { - - const logical::Class& clazz = node.getLimNode(); - set& niiSet = this->shared->currentClassInfo().sets[this->name]; - - // self references removed - for ( ListIterator hasMemberIt = clazz.getMemberListIteratorBegin(); hasMemberIt != clazz.getMemberListIteratorEnd(); ++hasMemberIt ) { - niiSet.erase( hasMemberIt->getId() ); - } - - addMetric( node, (int) this->shared->currentClassInfo().sets[this->name].size() ); - - cleanup( node ); - }); - - // C vs. C++ compat - registerHandler( phaseVisit, NTYPE_LIM_STRUCTURE, limLangC, false, [this] ( NodeWrapper& node ) { - setInvalid( node ); - }); - registerHandler( phaseVisit, NTYPE_LIM_UNION, limLangC, false, [this] ( NodeWrapper& node ) { - setInvalid( node ); - }); - - } - - void NII::fillIncomingMethodInvocations( const logical::Method& method, std::set& incomingInvocations, bool withInstances ) { - ListIterator it = this->shared->factory->getReverseEdges().constIteratorBegin( method.getId(), edkMethodCall_Method ); - for ( ; it != this->shared->factory->getReverseEdges().constIteratorEnd(method.getId(), edkMethodCall_Method); ++it ) { - if ( Common::getIsMethodCall( *it ) ) { - const logical::MethodCall& methodCall = (const logical::MethodCall&)(*it); - ListIterator itMcall = this->shared->factory->getReverseEdges().constIteratorBegin( methodCall.getId(), edkMethod_Calls ); - for(; itMcall != this->shared->factory->getReverseEdges().constIteratorEnd(methodCall.getId(), edkMethod_Calls); ++itMcall) { - if ( Common::getIsMethod( *itMcall ) ) { - const logical::Method& callerMethod = (const logical::Method&)(*itMcall); - if ( ! withInstances ) { - if ( Common::getIsMethodGenericInstance( callerMethod ) ) { - const logical::MethodGenericInstance& methodGenericInst = (const logical::MethodGenericInstance&)(callerMethod); - const logical::MethodGeneric* methodGeneric = Common::getMethodPrototype( this->shared->factory->getReverseEdges(), methodGenericInst ); - if( methodGeneric != NULL ) { - incomingInvocations.insert(methodGeneric->getId()); - } - } else { - incomingInvocations.insert(callerMethod.getId()); - } - } else { - incomingInvocations.insert(callerMethod.getId()); - } - } - } - ListIterator itAcall = this->shared->factory->getReverseEdges().constIteratorBegin( methodCall.getId(), edkAttribute_Calls ); - for ( ; itAcall != this->shared->factory->getReverseEdges().constIteratorEnd( methodCall.getId(), edkAttribute_Calls ); ++itAcall ) { - if ( Common::getIsAttribute( *itAcall ) ) { - const logical::Attribute& callerAttribute = (const logical::Attribute&)(*itAcall); - incomingInvocations.insert( callerAttribute.getId() ); - } - } - } - } - } - - const string& NII::translateLevel( Language language, const string& level ) const { - const string& newLevel = MetricHandler::translateLevel( language, level ); - - switch ( language ) { - case limLangCpp: - if ( - newLevel == NTYPE_LIM_CLASS || - newLevel == NTYPE_LIM_UNION || - newLevel == NTYPE_LIM_INTERFACE - ) { - return NTYPE_LIM_CLASS; - } - break; - - case limLangCsharp: - if ( - newLevel == NTYPE_LIM_CLASS || - newLevel == NTYPE_LIM_INTERFACE - ) { - return NTYPE_LIM_CLASS; - } - break; - default: - break; - } - - return newLevel; - } - -}}} diff --git a/lib/limmetrics/src/metrics/NL.cpp b/lib/limmetrics/src/metrics/NL.cpp deleted file mode 100644 index c178e60..0000000 --- a/lib/limmetrics/src/metrics/NL.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * This file is part of OpenStaticAnalyzer. - * - * Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged - * - * Licensed under Version 1.2 of the EUPL (the "Licence"); - * - * You may not use this work except in compliance with the Licence. - * - * You may obtain a copy of the Licence in the LICENSE file or at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ - -#include "../../inc/metrics/NL.h" - -#include - -using namespace std; -using namespace columbus::lim::asg; -using namespace columbus::graphsupport::graphconstants; - -namespace columbus { namespace lim { namespace metrics { - - NLBase::NLBase( const string& name, MetricDataTypes type, bool enabled ) : MetricHandler( name, type, enabled ) { - - // C vs. C++ compat - registerHandler( phaseVisit, NTYPE_LIM_STRUCTURE, limLangC, false, [this] ( NodeWrapper& node ) { - setInvalid( node ); - }); - registerHandler( phaseVisit, NTYPE_LIM_UNION, limLangC, false, [this] ( NodeWrapper& node ) { - setInvalid( node ); - }); - - // Method level - this->registerHandler( phaseVisit, NTYPE_LIM_METHOD, limLangOther, false, [this]( NodeWrapper& node ) { - addMetric( node, getValue( node.getLimNode() ) ); - }); - - // Class level - this->registerHandler( phaseVisit, NTYPE_LIM_CLASS, asg::limLangOther, false, [this]( NodeWrapper& node ) { - - int value = 0; - const logical::Class& clazz = node.getLimNode(); - - ListIterator i = clazz.getMemberListIteratorBegin(), end = clazz.getMemberListIteratorEnd(); - for ( ; i != end; ++i ) { - if ( Common::getIsMethod( *i ) ) { - value = max( value, getValue( dynamic_cast( *i ) ) ); - } - } - - addMetric( node, value ); - }); - } - - const string& NLBase::translateLevel( Language language, const string& level ) const { - const string& newLevel = MetricHandler::translateLevel( language, level ); - - switch ( language ) { - case limLangCpp: - if ( - newLevel == NTYPE_LIM_CLASS || - newLevel == NTYPE_LIM_UNION - ) { - return NTYPE_LIM_CLASS; - } - break; - default: - break; - } - - return newLevel; - } - - - NL::NL( bool enabled ) : NLBase( "NL", mdtInt, enabled ) {} - - int NL::getValue( const asg::logical::Method& method ) { - return method.getNestingLevel(); - } - - NLE::NLE( bool enabled ) : NLBase( "NLE", mdtInt, enabled ) {} - - int NLE::getValue( const asg::logical::Method& method ) { - return method.getNestingLevelElseIf(); - } - -}}} diff --git a/lib/python/inc/Factory.h b/lib/python/inc/Factory.h index 0d8baa7..6dd656c 100644 --- a/lib/python/inc/Factory.h +++ b/lib/python/inc/Factory.h @@ -241,8 +241,8 @@ namespace columbus { namespace python { namespace asg { const_iterator(const const_iterator& otherit) :containerIt (otherit.containerIt),fact(otherit.fact){} const_iterator& operator++() {containerIt++; while (containerIt != fact->container.end() && ((*containerIt == NULL) || fact->getIsFiltered(*containerIt))) containerIt++; return *this;} const_iterator operator++(int) {const_iterator tmp(*this); operator++(); return tmp;} - bool operator==(const const_iterator& rhs) {return containerIt==rhs.containerIt;} - bool operator!=(const const_iterator& rhs) {return containerIt!=rhs.containerIt;} + bool operator==(const const_iterator& rhs) const {return containerIt==rhs.containerIt;} + bool operator!=(const const_iterator& rhs) const {return containerIt!=rhs.containerIt;} const base::Base* operator*() {return *containerIt;} friend class Factory; }; diff --git a/wrapper/AbstractWrapperLib/src/abstractwrapper/AbstractArchive.cpp b/wrapper/AbstractWrapperLib/src/abstractwrapper/AbstractArchive.cpp index bcc73f2..68bfb27 100644 --- a/wrapper/AbstractWrapperLib/src/abstractwrapper/AbstractArchive.cpp +++ b/wrapper/AbstractWrapperLib/src/abstractwrapper/AbstractArchive.cpp @@ -106,13 +106,19 @@ namespace ColumbusWrappers { writeDebugMsg(ABSTRACT_ARCHIVE, CMSG_DEBUG_ARCHIVE_INPUT, inputFilename.c_str()); string astName = objectNameToAstName(inputFilename); inputFileList.push_back(astName); - - // handling of .comment files - string commentFile = astName + ".comment"; - if (common::pathFileExists(commentFile)) + + + vector extraFiles = { ".comment", ".err" }; + + for (const auto& extraFileExtension : extraFiles) { - inputFileList.push_back(commentFile); + string extraFileName = astName + extraFileExtension; + if (common::pathFileExists(extraFileName)) + { + inputFileList.push_back(extraFileName); + } } + } string inputfile_list = wrapper_temp_dir + DIRDIVSTRING + common::toString(getCurrentProcessId()) + "input.list"; diff --git a/wrapper/AbstractWrapperLib/src/abstractwrapper/AbstractCompiler.cpp b/wrapper/AbstractWrapperLib/src/abstractwrapper/AbstractCompiler.cpp index 575d7d7..f662d5a 100644 --- a/wrapper/AbstractWrapperLib/src/abstractwrapper/AbstractCompiler.cpp +++ b/wrapper/AbstractWrapperLib/src/abstractwrapper/AbstractCompiler.cpp @@ -139,10 +139,12 @@ namespace ColumbusWrappers { else if (dialect == "c++14" || dialect == "c++1y" || dialect == "gnu++14" || dialect == "gnu++1y") return "c++14"; else if (dialect == "c++17" || dialect == "c++1z" || dialect == "gnu++17" || dialect == "gnu++1z") - //return "c++17"; - return "c++14"; // the cppcheck does not know the c++17 + return "c++17"; + else if (dialect == "c++20" || dialect == "c++2a" || dialect == "gnu++20" || dialect == "gnu++2a") + return "c++20"; - return "c++11"; + + return "c++20"; } string getCANIniNameForCompiler(const string& compilerPath)