IDEA-99241 (Report package naming convention violations in the editor)

This commit is contained in:
Bas Leijdekkers
2013-10-09 11:53:13 +02:00
parent 8cdab66638
commit 2e10f33487
9 changed files with 212 additions and 14 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,6 +30,10 @@ import org.jetbrains.annotations.Nullable;
* complete graph of references between classes, methods and other elements in the scope
* selected for the analysis.
*
* Global inspections can use a shared local inspection tool for highlighting the cases
* that do not need global analysis in the editor by implementing {@link #getSharedLocalInspectionTool()}
* The shared local inspection tools shares settings and documentation with the global inspection tool.
*
* @author anna
* @see LocalInspectionTool
* @since 6.0
@@ -193,9 +197,25 @@ public abstract class GlobalInspectionTool extends InspectionProfileEntry {
return null;
}
// In some cases we can do highlighting in annotator or high. visitor based on global inspection
/**
* In some cases we can do highlighting in annotator or high. visitor based on global inspection or use a shared local inspection tool
*/
public boolean worksInBatchModeOnly() {
return true;
return getSharedLocalInspectionTool() != null;
}
/**
* Returns the local inspection tool used for highlighting in the editor. Meant for global inspections which have a local component.
* The local inspection tool is not required to report on the exact same problems, and naturally can't use global analysis. The local
* inspection tool is not used in batch mode.
*
* For example a global inspection that reports a package could have a local inspection tool which highlights
* the package statement in a file.
* @return
*/
@Nullable
public LocalInspectionTool getSharedLocalInspectionTool() {
return null;
}
public void initialize(@NotNull GlobalInspectionContext context) {
@@ -18,10 +18,12 @@ package com.intellij.codeInspection.ex;
import com.intellij.codeInspection.GlobalInspectionContext;
import com.intellij.codeInspection.GlobalInspectionTool;
import com.intellij.codeInspection.InspectionEP;
import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.reference.RefGraphAnnotator;
import com.intellij.codeInspection.reference.RefManagerImpl;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* User: anna
@@ -72,4 +74,13 @@ public class GlobalInspectionToolWrapper extends InspectionToolWrapper<GlobalIns
public boolean worksInBatchModeOnly() {
return getTool().worksInBatchModeOnly();
}
@Nullable
public LocalInspectionToolWrapper getSharedLocalInspectionToolWrapper() {
final LocalInspectionTool sharedTool = getTool().getSharedLocalInspectionTool();
if (sharedTool == null) {
return null;
}
return new LocalInspectionToolWrapper(sharedTool);
}
}
@@ -703,6 +703,10 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass
if (toolWrapper instanceof LocalInspectionToolWrapper) {
wrapper = (LocalInspectionToolWrapper)toolWrapper;
}
else if (toolWrapper instanceof GlobalInspectionToolWrapper) {
final GlobalInspectionToolWrapper globalInspectionToolWrapper = (GlobalInspectionToolWrapper)toolWrapper;
wrapper = globalInspectionToolWrapper.getSharedLocalInspectionToolWrapper();
}
if (wrapper == null) continue;
if (myIgnoreSuppressed) {
if (wrapper.isApplicable(language) && SuppressionUtil.inspectionResultSuppressed(myFile, wrapper.getTool())) {
@@ -1,5 +1,5 @@
/*
* Copyright 2003-2011 Dave Griffith, Bas Leijdekkers
* Copyright 2003-2013 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -48,7 +48,7 @@ public abstract class BaseInspection extends BaseJavaBatchLocalInspectionTool {
@Override
@NotNull
public final String getShortName() {
public String getShortName() {
if (m_shortName == null) {
final Class<? extends BaseInspection> aClass = getClass();
final String name = aClass.getName();
@@ -150,7 +150,7 @@ public abstract class BaseInspection extends BaseJavaBatchLocalInspectionTool {
for (List<String> out : outs) {
out.clear();
}
int iMax = strings.size();
final int iMax = strings.size();
for (int i = 0; i < iMax; i += outs.length) {
for (int j = 0; j < outs.length; j++) {
final List<String> out = outs[j];
@@ -0,0 +1,45 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.siyeh.ig;
import com.intellij.codeInspection.GlobalInspectionTool;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
/**
* @author Bas Leijdekkers
*/
public abstract class BaseSharedLocalInspection<T extends GlobalInspectionTool> extends BaseInspection {
protected final T mySettingsDelegate;
public BaseSharedLocalInspection(T settingsDelegate) {
mySettingsDelegate = settingsDelegate;
}
@NotNull
@Override
public final String getShortName() {
return mySettingsDelegate.getShortName();
}
@Nls
@NotNull
@Override
public final String getDisplayName() {
return mySettingsDelegate.getDisplayName();
}
}
@@ -19,12 +19,18 @@ import com.intellij.analysis.AnalysisScope;
import com.intellij.codeInspection.CommonProblemDescriptor;
import com.intellij.codeInspection.GlobalInspectionContext;
import com.intellij.codeInspection.InspectionManager;
import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.reference.RefEntity;
import com.intellij.codeInspection.reference.RefPackage;
import com.intellij.codeInspection.ui.ConventionOptionsPanel;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.psi.PsiJavaCodeReferenceElement;
import com.intellij.psi.PsiPackageStatement;
import com.siyeh.HardcodedMethodConstants;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseGlobalInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.BaseSharedLocalInspection;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -91,8 +97,7 @@ public class PackageNamingConventionInspection extends BaseGlobalInspection {
else {
final String errorString =
InspectionGadgetsBundle.message("package.naming.convention.problem.descriptor.regex.mismatch", name, m_regex);
return new CommonProblemDescriptor[]{
inspectionManager.createProblemDescriptor(errorString)};
return new CommonProblemDescriptor[]{inspectionManager.createProblemDescriptor(errorString)};
}
}
@@ -106,4 +111,76 @@ public class PackageNamingConventionInspection extends BaseGlobalInspection {
public JComponent createOptionsPanel() {
return new ConventionOptionsPanel(this, "m_minLength", "m_maxLength", "m_regex", "m_regexPattern");
}
boolean isValid(String name) {
final int length = name.length();
if (length < m_minLength) {
return false;
}
if (m_maxLength > 0 && length > m_maxLength) {
return false;
}
if (HardcodedMethodConstants.SERIAL_VERSION_UID.equals(name)) {
return true;
}
final Matcher matcher = m_regexPattern.matcher(name);
return matcher.matches();
}
@Nullable
public LocalInspectionTool getSharedLocalInspectionTool() {
return new LocalPackageNamingConventionInspection(this);
}
private static class LocalPackageNamingConventionInspection extends BaseSharedLocalInspection<PackageNamingConventionInspection> {
public LocalPackageNamingConventionInspection(PackageNamingConventionInspection inspection) {
super(inspection);
}
@NotNull
@Override
protected String buildErrorString(Object... infos) {
final String name = (String)infos[0];
if (name.length() < mySettingsDelegate.m_minLength) {
return InspectionGadgetsBundle.message("package.naming.convention.problem.descriptor.short", name);
}
else if (name.length() > mySettingsDelegate.m_maxLength) {
return InspectionGadgetsBundle.message("package.naming.convention.problem.descriptor.long", name);
}
else {
return InspectionGadgetsBundle.message("package.naming.convention.problem.descriptor.regex.mismatch",
name, mySettingsDelegate.m_regex);
}
}
@Override
public BaseInspectionVisitor buildVisitor() {
return new BaseInspectionVisitor() {
@Override
public void visitPackageStatement(PsiPackageStatement statement) {
final PsiJavaCodeReferenceElement reference = statement.getPackageReference();
if (reference == null) {
return;
}
final String text = reference.getText();
int start = 0;
int index = text.indexOf('.', start);
while (index > 0) {
final String name = text.substring(start, index);
if (!mySettingsDelegate.isValid(name)) {
registerErrorAtOffset(reference, start, index - start, name);
}
start = index + 1;
index = text.indexOf('.', start);
}
final String lastName = text.substring(start);
if (!mySettingsDelegate.isValid(lastName)) {
registerErrorAtOffset(reference, start, lastName.length(), lastName);
}
}
};
}
}
}
@@ -1,10 +1,10 @@
<html>
<body>
This global inspection reports packages whose names are either too short, too long, or do not follow
the specified regular expression pattern. Since this inspection requires global code analysis, it is only available in batch inspection mode.
the specified regular expression pattern.
<!-- tooltip end -->
<p>
Use the fields below to specify minimum length, maximum length and regular expression expected for method parameter names
Use the fields below to specify minimum length, maximum length and regular expression expected for package names
(Regular expressions are in standard <b>java.util.regex</b> format).
<p>
<small>New in 11</small>
@@ -15,8 +15,9 @@
*/
package com.siyeh.ig;
import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.InspectionProfileEntry;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
import com.intellij.util.ArrayUtil;
import org.intellij.lang.annotations.Language;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -36,11 +37,11 @@ public abstract class LightInspectionTestCase extends LightCodeInsightFixtureTes
myFixture.enableInspections(getInspection());
}
protected abstract LocalInspectionTool getInspection();
protected abstract InspectionProfileEntry getInspection();
@NonNls
protected String[] getEnvironmentClasses() {
return new String[]{};
return ArrayUtil.EMPTY_STRING_ARRAY;
}
protected void addEnvironmentClass(@Language("JAVA") @NotNull @NonNls String classText) {
@@ -82,7 +83,7 @@ public abstract class LightInspectionTestCase extends LightCodeInsightFixtureTes
@Override
protected String getBasePath() {
final Class<? extends LocalInspectionTool> inspectionClass = getInspection().getClass();
final Class<? extends InspectionProfileEntry> inspectionClass = getInspection().getClass();
final String className = inspectionClass.getName();
final String[] words = className.split("\\.");
@NonNls final StringBuilder basePath = new StringBuilder("/plugins/InspectionGadgets/test/");
@@ -0,0 +1,40 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* (c) 2013 Desert Island BV
* created: 09 10 2013
*/
package com.siyeh.ig.naming;
import com.intellij.codeInspection.InspectionProfileEntry;
import com.siyeh.ig.LightInspectionTestCase;
/**
* @author Bas Leijdekkers
*/
public class PackageNamingConventionInspectionTest extends LightInspectionTestCase {
public void testSharedLocalInspection() {
doTest("package /*Package name 'a' is too short*/a/**/./*Package name 'bbbbbbbbbbbbbbbbbbbb' is too long*/bbbbbbbbbbbbbbbbbbbb/**/;" +
"class X {}");
}
@Override
protected InspectionProfileEntry getInspection() {
return new PackageNamingConventionInspection();
}
}