1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-22 22:22:11 +02:00

Bug 545702 - Added new checker to verify copyright information

Change-Id: I57cad8565ce3c752a41f89473a95d5427d10cc8b
Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
This commit is contained in:
Marco Stornelli 2019-03-23 14:41:20 +01:00
parent 86bfd4de7e
commit f90cd7214d
7 changed files with 291 additions and 0 deletions

View file

@ -149,3 +149,8 @@ checker.name.GotoStatementChecker = Goto statement in source files checker
problem.name.GotoStatementProblem = Goto statement used
problem.messagePattern.GotoStatementProblem = Code that uses goto statements is harder to understand than alternative constructions
problem.description.GotoStatementProblem = This rule will flag goto statements in source files
checker.name.CopyrightChecker = Copyright in source code checker
problem.name.CopyrightProblem = Lack of copyright information
problem.messagePattern.CopyrightProblem = Copyright information missing
problem.description.CopyrightProblem = This rule will flag files without copyright information

View file

@ -484,5 +484,20 @@
name="%problem.name.GotoStatementProblem">
</problem>
</checker>
<checker
class="org.eclipse.cdt.codan.internal.checkers.CopyrightChecker"
id="org.eclipse.cdt.codan.internal.checkers.CopyrightChecker"
name="%checker.name.CopyrightChecker">
<problem
category="org.eclipse.cdt.codan.core.categories.CodeStyle"
defaultEnabled="false"
defaultSeverity="Warning"
description="%problem.description.CopyrightProblem"
id="org.eclipse.cdt.codan.internal.checkers.CopyrightProblem"
markerType="org.eclipse.cdt.codan.core.codanProblem"
messagePattern="%problem.messagePattern.CopyrightProblem"
name="%problem.name.CopyrightProblem">
</problem>
</checker>
</extension>
</plugin>

View file

@ -39,6 +39,8 @@ public class CheckersMessages extends NLS {
public static String UnusedSymbolInFileScopeChecker_CharacterSequence;
public static String UnusedSymbolInFileScopeChecker_Exceptions;
public static String Copyright_regex;
static {
NLS.initializeMessages(CheckersMessages.class.getName(), CheckersMessages.class);
}

View file

@ -30,3 +30,5 @@ SuspiciousSemicolonChecker_ParamElse=Do not report an error after 'if' when 'els
ProblemBindingChecker_Candidates=Candidates are:
UnusedSymbolInFileScopeChecker_CharacterSequence=Identifier character sequence:
UnusedSymbolInFileScopeChecker_Exceptions=Exceptions (identifier character sequence)
Copyright_regex=Regex to search for copyright information

View file

@ -0,0 +1,132 @@
/*******************************************************************************
* Copyright (c) 2019 Marco Stornelli
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
*******************************************************************************/
package org.eclipse.cdt.codan.internal.checkers;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.eclipse.cdt.codan.checkers.CodanCheckersActivator;
import org.eclipse.cdt.codan.core.cxx.model.AbstractIndexAstChecker;
import org.eclipse.cdt.codan.core.model.IProblem;
import org.eclipse.cdt.codan.core.model.IProblemLocation;
import org.eclipse.cdt.codan.core.model.IProblemLocationFactory;
import org.eclipse.cdt.codan.core.model.IProblemWorkingCopy;
import org.eclipse.cdt.core.dom.ast.IASTComment;
import org.eclipse.cdt.core.dom.ast.IASTNodeLocation;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
/**
* Checker for lack of copyright information
*/
public class CopyrightChecker extends AbstractIndexAstChecker {
public static final String ERR_ID = "org.eclipse.cdt.codan.internal.checkers.CopyrightProblem"; //$NON-NLS-1$
public static final String PARAM_REGEX = "regex"; //$NON-NLS-1$
private static final String DEF_REGEX = ".*Copyright.*"; //$NON-NLS-1$
private Pattern fPattern;
private StringBuilder builder = new StringBuilder();
private int lastOffset;
private boolean multiLine = false;
/**
* Internal result
* Not found: we didn't find a proper comment
* Found: we found a comment at line 1 but without match, we can stop the search
* Found match: comment at line 1 with matching regex
*/
private enum Result {
NOT_FOUND, FOUND, FOUND_MATCH;
}
@Override
public boolean runInEditor() {
return false;
}
@Override
public void processAst(IASTTranslationUnit ast) {
multiLine = false;
lastOffset = 0;
builder.setLength(0);
String regex = getRegex();
if (regex == null || regex.isEmpty())
regex = DEF_REGEX;
try {
fPattern = Pattern.compile(regex, Pattern.MULTILINE | Pattern.DOTALL);
} catch (PatternSyntaxException e) {
CodanCheckersActivator.log(e);
return;
}
IASTComment[] comments = ast.getComments();
if (comments == null) {
setProblem();
return;
}
Result found = Result.NOT_FOUND;
for (IASTComment comment : comments) {
found = processComment(comment);
if (found == Result.FOUND || found == Result.FOUND_MATCH)
break;
}
if (found == Result.NOT_FOUND && multiLine) {
String c = builder.toString();
if (!fPattern.matcher(c).matches()) {
setProblem();
}
} else if (found != Result.FOUND_MATCH)
setProblem();
}
@Override
public void initPreferences(IProblemWorkingCopy problem) {
super.initPreferences(problem);
addPreference(problem, PARAM_REGEX, CheckersMessages.Copyright_regex, DEF_REGEX);
}
public String getRegex() {
final IProblem pt = getProblemById(ERR_ID, getFile());
return (String) getPreference(pt, PARAM_REGEX);
}
protected Result processComment(IASTComment comment) {
if (comment.isPartOfTranslationUnitFile()) {
IASTNodeLocation nodeLocation = comment.getFileLocation();
if (nodeLocation == null) {
return Result.NOT_FOUND;
}
String c = comment.getRawSignature();
int currentOffset = nodeLocation.getNodeOffset();
if (!comment.isBlockComment() && c.startsWith("//") //$NON-NLS-1$
&& (currentOffset == lastOffset + 1 || (!multiLine && currentOffset == 0))) {
builder.append(c);
builder.append("\n"); //$NON-NLS-1$
lastOffset = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength();
multiLine = true;
return Result.NOT_FOUND;
}
if (multiLine) {
c = builder.toString();
} else if (nodeLocation.getNodeOffset() != 0) {
return Result.NOT_FOUND;
}
if (fPattern.matcher(c).matches())
return Result.FOUND_MATCH;
return Result.FOUND;
}
return Result.NOT_FOUND;
}
private void setProblem() {
IProblemLocationFactory locFactory = getRuntime().getProblemLocationFactory();
IProblemLocation p = locFactory.createProblemLocation(getFile(), 1);
reportProblem(ERR_ID, p);
}
}

View file

@ -0,0 +1,133 @@
/*******************************************************************************
* Copyright (c) 2019 Marco Stornelli
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.cdt.codan.core.internal.checkers;
import org.eclipse.cdt.codan.core.tests.CheckerTestCase;
import org.eclipse.cdt.codan.internal.checkers.CopyrightChecker;
/**
* Test for {@link CopyrightChecker} class
*/
public class CopyrightCheckerTest extends CheckerTestCase {
public static final String ERR_ID = CopyrightChecker.ERR_ID;
@Override
public void setUp() throws Exception {
super.setUp();
enableProblems(ERR_ID);
}
@Override
public boolean isCpp() {
return true;
}
//int main() {return 0;}
public void testWithoutCopyright() throws Exception {
loadCodeAndRun(getAboveComment());
checkErrorLine(1, ERR_ID);
}
////Copyright 2019
//int main() {return 0;}
public void testWithCopyright() throws Exception {
loadCodeAndRun(getAboveComment());
checkNoErrorsOfKind(ERR_ID);
}
////============================================================================
//// Name : test.cpp
//// Author : Blah
//// Version : 1.0
//// Copyright : Your copyright notice
//// Description : Hello World in C++, Ansi-style
////============================================================================
//
//int main() {return 0;}
public void testWithCopyrightMultiline() throws Exception {
loadCodeAndRun(getAboveComment());
checkNoErrorsOfKind(ERR_ID);
}
////============================================================================
//// Name : test.cpp
//// Author : Blah
//// Version : 1.0
//// Description : Hello World in C++, Ansi-style
////============================================================================
//
//int main() {return 0;}
public void testWithoutCopyrightMultiline() throws Exception {
loadCodeAndRun(getAboveComment());
checkErrorLine(1, ERR_ID);
}
//// Just another comment here
//
////============================================================================
//// Name : test.cpp
//// Author : Blah
//// Version : 1.0
//// Copyright : Your copyright notice
//// Description : Hello World in C++, Ansi-style
////============================================================================
//
//int main() {return 0;}
public void testWithCopyrightMultilineNoHeader() throws Exception {
loadCodeAndRun(getAboveComment());
checkErrorLine(1, ERR_ID);
}
////============================================================================
//// Name : test.cpp
//// Author : Blah
//// Version : 1.0
//// Copyright : Your copyright notice
//// Description : Hello World in C++, Ansi-style
////============================================================================
//
//// Just another comment here
//int main() {return 0;}
public void testWithCopyrightMultilinePostComment() throws Exception {
loadCodeAndRun(getAboveComment());
checkNoErrorsOfKind(ERR_ID);
}
///****************************************************************************
// * Name : test.cpp
// * Author : Blah
// * Version : 1.0
// * Copyright : Your copyright notice
// * Description : Hello World in C++, Ansi-style
// ****************************************************************************/
//
//int main() {return 0;}
public void testWithCopyrightBlock() throws Exception {
loadCodeAndRun(getAboveComment());
checkNoErrorsOfKind(ERR_ID);
}
//// Just another comment here
///****************************************************************************
// * Name : test.cpp
// * Author : Blah
// * Version : 1.0
// * Copyright : Your copyright notice
// * Description : Hello World in C++, Ansi-style
// ****************************************************************************/
//
//int main() {return 0;}
public void testWithCopyrightBlockNoHeader() throws Exception {
loadCodeAndRun(getAboveComment());
checkErrorLine(1, ERR_ID);
}
}

View file

@ -23,6 +23,7 @@ import org.eclipse.cdt.codan.core.internal.checkers.CatchByReferenceTest;
import org.eclipse.cdt.codan.core.internal.checkers.ClassMembersInitializationCheckerTest;
import org.eclipse.cdt.codan.core.internal.checkers.CommentCheckerLineTests;
import org.eclipse.cdt.codan.core.internal.checkers.CommentCheckerNestedTests;
import org.eclipse.cdt.codan.core.internal.checkers.CopyrightCheckerTest;
import org.eclipse.cdt.codan.core.internal.checkers.DecltypeAutoCheckerTest;
import org.eclipse.cdt.codan.core.internal.checkers.FormatStringCheckerTest;
import org.eclipse.cdt.codan.core.internal.checkers.GotoStatementCheckerTest;
@ -86,6 +87,7 @@ public class AutomatedIntegrationSuite extends TestSuite {
suite.addTestSuite(CommentCheckerLineTests.class);
suite.addTestSuite(CommentCheckerNestedTests.class);
suite.addTestSuite(GotoStatementCheckerTest.class);
suite.addTestSuite(CopyrightCheckerTest.class);
// framework
suite.addTest(CodanFastTestSuite.suite());
// quick fixes