diff --git a/cxx-checks/src/main/java/org/sonar/cxx/checks/CheckList.java b/cxx-checks/src/main/java/org/sonar/cxx/checks/CheckList.java index 94cb06821e..1662ac27f1 100644 --- a/cxx-checks/src/main/java/org/sonar/cxx/checks/CheckList.java +++ b/cxx-checks/src/main/java/org/sonar/cxx/checks/CheckList.java @@ -72,7 +72,8 @@ public static List getChecks() { SafetyTagCheck.class, UseCorrectIncludeCheck.class, XPathCheck.class, - BooleanEqualityComparisonCheck.class + BooleanEqualityComparisonCheck.class, + CompileIncludePathNotFoundOrInvalid.class ); } diff --git a/cxx-checks/src/main/java/org/sonar/cxx/checks/CompileIncludePathNotFoundOrInvalid.java b/cxx-checks/src/main/java/org/sonar/cxx/checks/CompileIncludePathNotFoundOrInvalid.java index 92d4b6b859..922a2ec2e9 100644 --- a/cxx-checks/src/main/java/org/sonar/cxx/checks/CompileIncludePathNotFoundOrInvalid.java +++ b/cxx-checks/src/main/java/org/sonar/cxx/checks/CompileIncludePathNotFoundOrInvalid.java @@ -42,7 +42,8 @@ key = "CompileIncludePathNotFoundOrInvalid", name = "Include path used during compilation not found or invalid", tags = {Tags.PREPROCESSOR}, - priority = Priority.MAJOR) + description = "Verifies that include files used by compiler exist", + priority = Priority.INFO) @ActivatedByDefault @SqaleSubCharacteristic(RulesDefinition.SubCharacteristics.ARCHITECTURE_RELIABILITY) @SqaleConstantRemediation("5min") diff --git a/cxx-checks/src/test/java/org/sonar/cxx/checks/CheckListTest.java b/cxx-checks/src/test/java/org/sonar/cxx/checks/CheckListTest.java index 6375ea06b7..43e609a8ee 100644 --- a/cxx-checks/src/test/java/org/sonar/cxx/checks/CheckListTest.java +++ b/cxx-checks/src/test/java/org/sonar/cxx/checks/CheckListTest.java @@ -27,6 +27,6 @@ public class CheckListTest { @Test public void count() { - assertThat(CheckList.getChecks().size()).isEqualTo(39); + assertThat(CheckList.getChecks().size()).isEqualTo(40); } } diff --git a/cxx-squid/src/main/java/org/sonar/cxx/CxxConfiguration.java b/cxx-squid/src/main/java/org/sonar/cxx/CxxConfiguration.java index c90be2f211..d49c72865b 100644 --- a/cxx-squid/src/main/java/org/sonar/cxx/CxxConfiguration.java +++ b/cxx-squid/src/main/java/org/sonar/cxx/CxxConfiguration.java @@ -255,20 +255,24 @@ private void RaiseIssuesForNotFoundIncludes(ActiveRule rule, FileSystem fs ) { if(!entry.getKey().equals(OverallIncludeKey)) { for(String value : entry.getValue()) { - File directory = new File(value); - if (!directory.exists()) { - InputFile sonarFile = fs.inputFile(fs.predicates().hasAbsolutePath(value)); - Issuable issuable = perspectives.as(Issuable.class, sonarFile); - if ((issuable != null) && (rule != null)) { - Issue issue = issuable.newIssueBuilder() - .ruleKey(rule.ruleKey()) - .line(1) - .message("Remove include from poject files, \"" + value + "\" it does not exist.") - .build(); - issuable.addIssue(issue); + try + { + File directory = new File(entry.getKey()); + if (!directory.exists()) { + InputFile sonarFile = fs.inputFile(fs.predicates().hasAbsolutePath(value)); + Issuable issuable = perspectives.as(Issuable.class, sonarFile); + if ((issuable != null) && (rule != null)) { + Issue issue = issuable.newIssueBuilder() + .ruleKey(rule.ruleKey()) + .line(1) + .message("Remove include from poject files, \"" + value + "\" it does not exist.") + .build(); + issuable.addIssue(issue); + } } + } catch(IllegalArgumentException ex) { + LOG.warn("Cannot Create Issue for: '{}' reason: '{}'", value, ex.getMessage()); } - } } } diff --git a/cxx-squid/src/main/java/org/sonar/cxx/CxxVCppBuildLogParser.java b/cxx-squid/src/main/java/org/sonar/cxx/CxxVCppBuildLogParser.java index 88530f6201..c522b32d16 100644 --- a/cxx-squid/src/main/java/org/sonar/cxx/CxxVCppBuildLogParser.java +++ b/cxx-squid/src/main/java/org/sonar/cxx/CxxVCppBuildLogParser.java @@ -24,6 +24,8 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; +import java.nio.file.InvalidPathException; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; @@ -56,7 +58,7 @@ public void parseVCppLog(File buildLog, String charsetName) { try { BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(buildLog), charsetName)); String line; - String currentProjectPath = ""; + Path currentProjectPath = Paths.get("."); Set overallIncludes = uniqueIncludes.get(CxxConfiguration.OverallIncludeKey); @@ -73,7 +75,10 @@ public void parseVCppLog(File buildLog, String charsetName) { // get base path of project to make // Target "ClCompile" in file "C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\Microsoft.CppCommon.targets" from project "D:\Development\SonarQube\cxx\sonar-cxx\integration-tests\testdata\googletest_bullseye_vs_project\PathHandling.Test\PathHandling.Test.vcxproj" (target "_ClCompile" depends on it): if (line.startsWith("Target \"ClCompile\" in file")) { - currentProjectPath = line.split("\" from project \"")[1].split("\\s+")[0].replace("\"", ""); + currentProjectPath = Paths.get(line.split("\" from project \"")[1].split("\\s+")[0].replace("\"", "")).getParent(); + if (currentProjectPath == null) { + currentProjectPath = Paths.get("."); + } } if(line.contains("\\V100\\Microsoft.CppBuild.targets")) { @@ -97,33 +102,43 @@ public void parseVCppLog(File buildLog, String charsetName) { if (line.contains("\\bin\\CL.exe")) { String[] allElems = line.split("\\s+"); - String fileElement = Paths.get(currentProjectPath, allElems[allElems.length - 1]).toAbsolutePath().toString(); - if (!uniqueDefines.containsKey(fileElement)) { - uniqueDefines.put(fileElement, new HashSet()); - } - if (!uniqueIncludes.containsKey(fileElement)) { - uniqueIncludes.put(fileElement, new HashSet()); + String data = allElems[allElems.length - 1]; + try { + String fileElement = Paths.get(currentProjectPath.toAbsolutePath().toString(), data).toAbsolutePath().toString(); + + if (!uniqueDefines.containsKey(fileElement)) { + uniqueDefines.put(fileElement, new HashSet()); + } + + if (!uniqueIncludes.containsKey(fileElement)) { + uniqueIncludes.put(fileElement, new HashSet()); + } + + parseVCppCompilerCLLine(line, currentProjectPath.toAbsolutePath().toString(), fileElement); + } catch (InvalidPathException ex) { + LOG.warn("Cannot extract information from current element: " + data + " : " + ex.getMessage()); + } catch (NullPointerException ex) { + LOG.error("Bug in parser, please report: '{}' - '{}'", ex.getMessage(), data + " @ " + currentProjectPath); + LOG.error("StackTrace: '{}'", ex.getStackTrace()); } - parseVCppCompilerCLLine(line, currentProjectPath, fileElement); + } } br.close(); } catch (IOException ex) { LOG.error("Cannot parse build log", ex); - } + } } private void parseVCppCompilerCLLine(String line, String projectPath, String fileElement) { - File file = new File(projectPath); - String project = file.getParent(); for (String includeElem : getMatches(Pattern.compile("/I\"(.*?)\""), line)) { - ParseInclude(includeElem, project, fileElement); + ParseInclude(includeElem, projectPath, fileElement); } for (String includeElem : getMatches(Pattern.compile("/I([^\\s\"]+) "), line)) { - ParseInclude(includeElem, project, fileElement); + ParseInclude(includeElem, projectPath, fileElement); } for (String macroElem : getMatches(Pattern.compile("[/-]D\\s([^\\s]+)"), @@ -197,33 +212,33 @@ private void AddMacro(String macroElem, String file) { private void ParseCommonCompilerOptions(String line, String fileElement) { // Always Defined // //_INTEGRAL_MAX_BITS Reports the maximum size (in bits) for an integral type. - AddMacro("_INTEGRAL_MAX_BITS", fileElement); + AddMacro("_INTEGRAL_MAX_BITS=32", fileElement); //_MFC_VER Defines the MFC version. For example, in Visual Studio 2010, _MFC_VER is defined as 0x0A00. - AddMacro("_MFC_VER", fileElement); + AddMacro("_MFC_VER=1", fileElement); //_MSC_BUILD Evaluates to the revision number component of the compiler's version number. The revision number is the fourth component of the period-delimited version number. For example, if the version number of the Visual C++ compiler is 15.00.20706.01, the _MSC_BUILD macro evaluates to 1. - AddMacro("_MSC_BUILD", fileElement); + AddMacro("_MSC_BUILD=1", fileElement); //_MSC_FULL_VER Evaluates to the major, minor, and build number components of the compiler's version number. The major number is the first component of the period-delimited version number, the minor number is the second component, and the build number is the third component. For example, if the version number of the Visual C++ compiler is 15.00.20706.01, the _MSC_FULL_VER macro evaluates to 150020706. Type cl /? at the command line to view the compiler's version number. - AddMacro("_MSC_FULL_VER", fileElement); + AddMacro("_MSC_FULL_VER=150020706", fileElement); //_MSC_VER Evaluates to the major and minor number components of the compiler's version number. The major number is the first component of the period-delimited version number and the minor number is the second component. - AddMacro("_MSC_VER", fileElement); + AddMacro("_MSC_VER=1700", fileElement); //__COUNTER__ Expands to an integer starting with 0 and incrementing by 1 every time it is used in a source file or included headers of the source file. __COUNTER__ remembers its state when you use precompiled headers. - AddMacro("__COUNTER__", fileElement); + AddMacro("__COUNTER__=0", fileElement); //__DATE__ The compilation date of the current source file. The date is a string literal of the form Mmm dd yyyy. The month name Mmm is the same as for dates generated by the library function asctime declared in TIME.H. - AddMacro("__DATE__", fileElement); + AddMacro("__DATE__=\"??? ?? ????\"", fileElement); //__FILE__ The name of the current source file. __FILE__ expands to a string surrounded by double quotation marks. To ensure that the full path to the file is displayed, use /FC (Full Path of Source Code File in Diagnostics). - AddMacro("__FILE__", fileElement); + AddMacro("__FILE__=\"file\"", fileElement); //__LINE__ The line number in the current source file. The line number is a decimal integer constant. It can be changed with a #line directive. - AddMacro("__LINE__", fileElement); + AddMacro("__LINE__=1", fileElement); //__TIME__ The most recent compilation time of the current source file. The time is a string literal of the form hh:mm:ss. - AddMacro("__TIME__", fileElement); + AddMacro("__TIME__=\"??:??:??\"", fileElement); //__TIMESTAMP__ The date and time of the last modification of the current source file, expressed as a string literal in the form Ddd Mmm Date hh:mm:ss yyyy, where Ddd is the abbreviated day of the week and Date is an integer from 1 to 31. - AddMacro("__TIMESTAMP__", fileElement); + AddMacro("__TIMESTAMP__=\"??? ?? ???? ??:??:??\"", fileElement); //_ATL_VER Defines the ATL version. In Visual Studio 2010, _ATL_VER is defined as 0x0A00. - AddMacro("_ATL_VER", fileElement); + AddMacro("_ATL_VER=1", fileElement); //__STDC__ Indicates full conformance with the ANSI C standard. Defined as the integer constant 1 only if the /Za compiler option is given and you are not compiling C++ code; otherwise is undefined. if (line.contains("/Za ")) { - AddMacro("__STDC__", fileElement); + AddMacro("__STDC__=1", fileElement); } //_CHAR_UNSIGNED Default char type is unsigned. Defined when /J is specified. diff --git a/cxx-squid/src/main/java/org/sonar/cxx/preprocessor/ExpressionEvaluator.java b/cxx-squid/src/main/java/org/sonar/cxx/preprocessor/ExpressionEvaluator.java index 0cabc5f6e7..6341e6d113 100644 --- a/cxx-squid/src/main/java/org/sonar/cxx/preprocessor/ExpressionEvaluator.java +++ b/cxx-squid/src/main/java/org/sonar/cxx/preprocessor/ExpressionEvaluator.java @@ -45,19 +45,24 @@ public ExpressionEvaluator(CxxConfiguration conf, CxxPreprocessor preprocessor) } public boolean eval(String constExpr) { - return evalToInt(constExpr).compareTo(BigInteger.ZERO) != 0; + return evalToInt(constExpr, null).compareTo(BigInteger.ZERO) != 0; } public boolean eval(AstNode constExpr) { return evalToInt(constExpr).compareTo(BigInteger.ZERO) != 0; } - private BigInteger evalToInt(String constExpr) { + private BigInteger evalToInt(String constExpr, AstNode exprAst) { AstNode constExprAst = null; try { constExprAst = parser.parse(constExpr); } catch (com.sonar.sslr.api.RecognitionException re) { - LOG.warn("Error evaluating expression '{}', assuming 0", constExpr); + if (exprAst != null) { + LOG.warn("Error evaluating expression '{}' for AstExp '{}', assuming 0", constExpr, exprAst.getToken()); + } else { + LOG.warn("Error evaluating expression '{}', assuming 0", constExpr); + } + return BigInteger.ZERO; } @@ -87,7 +92,7 @@ private BigInteger evalLeaf(AstNode exprAst) { return evalCharacter(exprAst.getTokenValue()); } else if ("IDENTIFIER".equals(nodeType)) { String value = preprocessor.valueOf(exprAst.getTokenValue()); - return value == null ? BigInteger.ZERO : evalToInt(value); + return value == null ? BigInteger.ZERO : evalToInt(value, exprAst); } else { throw new EvaluationException("Unknown expression type '" + nodeType + "'"); } @@ -423,7 +428,7 @@ BigInteger evalFunctionlikeMacro(AstNode exprAst) { LOG.warn("Undefined functionlike macro '{}' assuming 0", macroName); } - return value == null ? BigInteger.ZERO : evalToInt(value); + return value == null ? BigInteger.ZERO : evalToInt(value, exprAst); } String stripSuffix(String number)