Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 56bff9a5cf |
+9
-11
@@ -18,7 +18,6 @@ import org.jetbrains.uast.UMethod;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@SuppressWarnings("UnstableApiUsage")
|
|
||||||
public final class ControllerChangeHandlerIssueDetector extends Detector implements Detector.UastScanner {
|
public final class ControllerChangeHandlerIssueDetector extends Detector implements Detector.UastScanner {
|
||||||
|
|
||||||
static final Issue ISSUE =
|
static final Issue ISSUE =
|
||||||
@@ -32,7 +31,7 @@ public final class ControllerChangeHandlerIssueDetector extends Detector impleme
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Class<? extends UElement>> getApplicableUastTypes() {
|
public List<Class<? extends UElement>> getApplicableUastTypes() {
|
||||||
return Collections.<Class<? extends UElement>>singletonList(UClass.class);
|
return Collections.singletonList(UClass.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -47,42 +46,41 @@ public final class ControllerChangeHandlerIssueDetector extends Detector impleme
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final boolean hasSuperType = evaluator.extendsClass(node.getPsi(), CLASS_NAME, true);
|
final boolean hasSuperType = evaluator.extendsClass(node.getJavaPsi(), CLASS_NAME, true);
|
||||||
if (!hasSuperType) {
|
if (!hasSuperType) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!evaluator.isPublic(node)) {
|
if (!evaluator.isPublic(node)) {
|
||||||
String message = String.format("This ControllerChangeHandler class should be public (%1$s)", node.getQualifiedName());
|
String message = String.format("This ControllerChangeHandler class should be public (%1$s)", node.getQualifiedName());
|
||||||
context.report(ISSUE, node, context.getLocation((UElement) node), message);
|
context.report(ISSUE, node, context.getLocation(Identify.byName(node)), message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.getContainingClass() != null && !evaluator.isStatic(node)) {
|
if (node.getContainingClass() != null && !evaluator.isStatic(node)) {
|
||||||
String message = String.format("This ControllerChangeHandler inner class should be static (%1$s)", node.getQualifiedName());
|
String message = String.format("This ControllerChangeHandler inner class should be static (%1$s)", node.getQualifiedName());
|
||||||
context.report(ISSUE, node, context.getLocation((UElement) node), message);
|
context.report(ISSUE, node, context.getLocation(Identify.byName(node)), message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean hasConstructor = false;
|
UMethod constructor = null;
|
||||||
boolean hasDefaultConstructor = false;
|
boolean hasDefaultConstructor = false;
|
||||||
for (UMethod method : node.getMethods()) {
|
for (UMethod method : node.getMethods()) {
|
||||||
if (method.isConstructor()) {
|
if (method.isConstructor()) {
|
||||||
hasConstructor = true;
|
constructor = method;
|
||||||
if (evaluator.isPublic(method) && method.getUastParameters().size() == 0) {
|
if (evaluator.isPublic(method) && method.getUastParameters().isEmpty()) {
|
||||||
hasDefaultConstructor = true;
|
hasDefaultConstructor = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasConstructor && !hasDefaultConstructor) {
|
if (constructor != null && !hasDefaultConstructor) {
|
||||||
String message = String.format(
|
String message = String.format(
|
||||||
"This ControllerChangeHandler needs to have a public default constructor (`%1$s`)", node.getQualifiedName());
|
"This ControllerChangeHandler needs to have a public default constructor (`%1$s`)", node.getQualifiedName());
|
||||||
context.report(ISSUE, node, context.getLocation((UElement) node), message);
|
context.report(ISSUE, node, context.getLocation(Identify.byName(constructor)), message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-14
@@ -10,6 +10,7 @@ import com.android.tools.lint.detector.api.Issue;
|
|||||||
import com.android.tools.lint.detector.api.JavaContext;
|
import com.android.tools.lint.detector.api.JavaContext;
|
||||||
import com.android.tools.lint.detector.api.Scope;
|
import com.android.tools.lint.detector.api.Scope;
|
||||||
import com.android.tools.lint.detector.api.Severity;
|
import com.android.tools.lint.detector.api.Severity;
|
||||||
|
import com.intellij.psi.PsiType;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.uast.UClass;
|
import org.jetbrains.uast.UClass;
|
||||||
@@ -20,7 +21,6 @@ import org.jetbrains.uast.UParameter;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@SuppressWarnings("UnstableApiUsage")
|
|
||||||
public final class ControllerIssueDetector extends Detector implements Detector.UastScanner {
|
public final class ControllerIssueDetector extends Detector implements Detector.UastScanner {
|
||||||
|
|
||||||
static final Issue ISSUE =
|
static final Issue ISSUE =
|
||||||
@@ -48,52 +48,53 @@ public final class ControllerIssueDetector extends Detector implements Detector.
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final boolean hasSuperType = evaluator.extendsClass(node.getPsi(), CLASS_NAME, true);
|
final boolean hasSuperType = evaluator.extendsClass(node.getJavaPsi(), CLASS_NAME, true);
|
||||||
if (!hasSuperType) {
|
if (!hasSuperType) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!evaluator.isPublic(node)) {
|
if (!evaluator.isPublic(node)) {
|
||||||
String message = String.format("This Controller class should be public (%1$s)", node.getQualifiedName());
|
String message = String.format("This Controller class should be public (%1$s)", node.getQualifiedName());
|
||||||
context.report(ISSUE, node, context.getLocation((UElement) node), message);
|
context.report(ISSUE, node, context.getLocation(Identify.byName(node)), message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.getContainingClass() != null && !evaluator.isStatic(node)) {
|
if (node.getContainingClass() != null && !evaluator.isStatic(node)) {
|
||||||
String message = String.format("This Controller inner class should be static (%1$s)", node.getQualifiedName());
|
String message = String.format("This Controller inner class should be static (%1$s)", node.getQualifiedName());
|
||||||
context.report(ISSUE, node, context.getLocation((UElement) node), message);
|
context.report(ISSUE, node, context.getLocation(Identify.byName(node)), message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean hasConstructor = false;
|
UMethod constructor = null;
|
||||||
boolean hasDefaultConstructor = false;
|
boolean hasDefaultConstructor = false;
|
||||||
boolean hasBundleConstructor = false;
|
boolean hasBundleConstructor = false;
|
||||||
for (UMethod method : node.getMethods()) {
|
for (UMethod method : node.getMethods()) {
|
||||||
if (method.isConstructor()) {
|
if (method.isConstructor()) {
|
||||||
hasConstructor = true;
|
constructor = method;
|
||||||
if (evaluator.isPublic(method)) {
|
if (evaluator.isPublic(method)) {
|
||||||
List<UParameter> parameters = method.getUastParameters();
|
List<UParameter> parameters = method.getUastParameters();
|
||||||
if (parameters.size() == 0) {
|
if (parameters.isEmpty()) {
|
||||||
hasDefaultConstructor = true;
|
hasDefaultConstructor = true;
|
||||||
break;
|
break;
|
||||||
} else if (parameters.size() == 1 &&
|
} else if (parameters.size() == 1) {
|
||||||
(parameters.get(0).getType().equalsToText(SdkConstants.CLASS_BUNDLE)) ||
|
PsiType type = parameters.get(0).getType();
|
||||||
parameters.get(0).getType().equalsToText("Bundle")) {
|
if (type.equalsToText(SdkConstants.CLASS_BUNDLE) || type.equalsToText("Bundle")) {
|
||||||
hasBundleConstructor = true;
|
hasBundleConstructor = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasConstructor && !hasDefaultConstructor && !hasBundleConstructor) {
|
if (constructor != null && !hasDefaultConstructor && !hasBundleConstructor) {
|
||||||
String message = String.format(
|
String message = String.format(
|
||||||
"This Controller needs to have either a public default constructor or a" +
|
"This Controller needs to have either a public default constructor or a" +
|
||||||
" public single-argument constructor that takes a Bundle. (`%1$s`)",
|
" public single-argument constructor that takes a Bundle. (`%1$s`)",
|
||||||
node.getQualifiedName());
|
node.getQualifiedName());
|
||||||
context.report(ISSUE, node, context.getLocation((UElement) node), message);
|
context.report(ISSUE, node, context.getLocation(Identify.byName(constructor)), message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.bluelinelabs.conductor.lint;
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
|
import com.intellij.psi.PsiNameIdentifierOwner;
|
||||||
|
|
||||||
|
final class Identify {
|
||||||
|
private Identify() {}
|
||||||
|
|
||||||
|
static PsiElement byName(PsiNameIdentifierOwner psiNameIdentifierOwner) {
|
||||||
|
if (psiNameIdentifierOwner.getNameIdentifier() != null) {
|
||||||
|
return psiNameIdentifierOwner.getNameIdentifier();
|
||||||
|
}
|
||||||
|
return psiNameIdentifierOwner;
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
-11
@@ -8,15 +8,8 @@ import com.android.tools.lint.checks.infrastructure.TestFile;
|
|||||||
import org.intellij.lang.annotations.Language;
|
import org.intellij.lang.annotations.Language;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@SuppressWarnings("UnstableApiUsage")
|
|
||||||
public class ControllerChangeHandlerDetectorTest {
|
public class ControllerChangeHandlerDetectorTest {
|
||||||
|
|
||||||
private static final String CONSTRUCTOR =
|
|
||||||
"src/test/SampleHandler.java:2: Error: This ControllerChangeHandler needs to have a public default constructor (test.SampleHandler) [ValidControllerChangeHandler]\n"
|
|
||||||
+ "public class SampleHandler extends com.bluelinelabs.conductor.ControllerChangeHandler {\n"
|
|
||||||
+ "^\n"
|
|
||||||
+ "1 errors, 0 warnings\n";
|
|
||||||
|
|
||||||
private final TestFile controllerChangeHandlerStub = java(
|
private final TestFile controllerChangeHandlerStub = java(
|
||||||
"package com.bluelinelabs.conductor;\n"
|
"package com.bluelinelabs.conductor;\n"
|
||||||
+ "abstract class ControllerChangeHandler {}"
|
+ "abstract class ControllerChangeHandler {}"
|
||||||
@@ -63,7 +56,12 @@ public class ControllerChangeHandlerDetectorTest {
|
|||||||
.files(controllerChangeHandlerStub, java(source))
|
.files(controllerChangeHandlerStub, java(source))
|
||||||
.issues(ControllerIssueDetector.ISSUE, ControllerChangeHandlerIssueDetector.ISSUE)
|
.issues(ControllerIssueDetector.ISSUE, ControllerChangeHandlerIssueDetector.ISSUE)
|
||||||
.run()
|
.run()
|
||||||
.expect(CONSTRUCTOR);
|
.expect(""
|
||||||
|
+ "src/test/SampleHandler.java:3: Error: This ControllerChangeHandler needs to have a public default constructor (test.SampleHandler) [ValidControllerChangeHandler]\n"
|
||||||
|
+ " public SampleHandler(int number) { }\n"
|
||||||
|
+ " ~~~~~~~~~~~~~\n"
|
||||||
|
+ "1 errors, 0 warnings\n"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -94,7 +92,12 @@ public class ControllerChangeHandlerDetectorTest {
|
|||||||
.files(controllerChangeHandlerStub, java(source))
|
.files(controllerChangeHandlerStub, java(source))
|
||||||
.issues(ControllerIssueDetector.ISSUE, ControllerChangeHandlerIssueDetector.ISSUE)
|
.issues(ControllerIssueDetector.ISSUE, ControllerChangeHandlerIssueDetector.ISSUE)
|
||||||
.run()
|
.run()
|
||||||
.expect(CONSTRUCTOR);
|
.expect(""
|
||||||
|
+ "src/test/SampleHandler.java:3: Error: This ControllerChangeHandler needs to have a public default constructor (test.SampleHandler) [ValidControllerChangeHandler]\n"
|
||||||
|
+ " private SampleHandler() { }\n"
|
||||||
|
+ " ~~~~~~~~~~~~~\n"
|
||||||
|
+ "1 errors, 0 warnings\n"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -111,7 +114,7 @@ public class ControllerChangeHandlerDetectorTest {
|
|||||||
.run()
|
.run()
|
||||||
.expect("src/test/SampleHandler.java:2: Error: This ControllerChangeHandler class should be public (test.SampleHandler) [ValidControllerChangeHandler]\n"
|
.expect("src/test/SampleHandler.java:2: Error: This ControllerChangeHandler class should be public (test.SampleHandler) [ValidControllerChangeHandler]\n"
|
||||||
+ "private class SampleHandler extends com.bluelinelabs.conductor.ControllerChangeHandler {\n"
|
+ "private class SampleHandler extends com.bluelinelabs.conductor.ControllerChangeHandler {\n"
|
||||||
+ "^\n"
|
+ " ~~~~~~~~~~~~~\n"
|
||||||
+ "1 errors, 0 warnings\n");
|
+ "1 errors, 0 warnings\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +134,7 @@ public class ControllerChangeHandlerDetectorTest {
|
|||||||
.run()
|
.run()
|
||||||
.expect("src/test/SampleHandler.java:2: Error: This ControllerChangeHandler class should be public (test.SampleHandler) [ValidControllerChangeHandler]\n" +
|
.expect("src/test/SampleHandler.java:2: Error: This ControllerChangeHandler class should be public (test.SampleHandler) [ValidControllerChangeHandler]\n" +
|
||||||
"private class SampleHandler extends test.BaseChangeHandler {}\n" +
|
"private class SampleHandler extends test.BaseChangeHandler {}\n" +
|
||||||
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" +
|
" ~~~~~~~~~~~~~\n" +
|
||||||
"1 errors, 0 warnings");
|
"1 errors, 0 warnings");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-14
@@ -8,18 +8,12 @@ import com.android.tools.lint.checks.infrastructure.TestFile;
|
|||||||
import org.intellij.lang.annotations.Language;
|
import org.intellij.lang.annotations.Language;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@SuppressWarnings("UnstableApiUsage")
|
|
||||||
public class ControllerDetectorTest {
|
public class ControllerDetectorTest {
|
||||||
|
|
||||||
private static final String CONSTRUCTOR_ERROR =
|
|
||||||
"src/test/SampleController.java:2: Error: This Controller needs to have either a public default constructor or a public single-argument constructor that takes a Bundle. (test.SampleController) [ValidController]\n"
|
|
||||||
+ "public class SampleController extends com.bluelinelabs.conductor.Controller {\n"
|
|
||||||
+ "^\n"
|
|
||||||
+ "1 errors, 0 warnings\n";
|
|
||||||
private static final String CLASS_ERROR =
|
private static final String CLASS_ERROR =
|
||||||
"src/test/SampleController.java:2: Error: This Controller class should be public (test.SampleController) [ValidController]\n"
|
"src/test/SampleController.java:2: Error: This Controller class should be public (test.SampleController) [ValidController]\n"
|
||||||
+ "private class SampleController extends com.bluelinelabs.conductor.Controller {\n"
|
+ "private class SampleController extends com.bluelinelabs.conductor.Controller {\n"
|
||||||
+ "^\n"
|
+ " ~~~~~~~~~~~~~~~~\n"
|
||||||
+ "1 errors, 0 warnings\n";
|
+ "1 errors, 0 warnings\n";
|
||||||
|
|
||||||
private final TestFile controllerStub = java(
|
private final TestFile controllerStub = java(
|
||||||
@@ -69,7 +63,12 @@ public class ControllerDetectorTest {
|
|||||||
.files(controllerStub, java(source))
|
.files(controllerStub, java(source))
|
||||||
.issues(ControllerIssueDetector.ISSUE, ControllerChangeHandlerIssueDetector.ISSUE)
|
.issues(ControllerIssueDetector.ISSUE, ControllerChangeHandlerIssueDetector.ISSUE)
|
||||||
.run()
|
.run()
|
||||||
.expect(CONSTRUCTOR_ERROR);
|
.expect(""
|
||||||
|
+ "src/test/SampleController.java:3: Error: This Controller needs to have either a public default constructor or a public single-argument constructor that takes a Bundle. (test.SampleController) [ValidController]\n"
|
||||||
|
+ " public SampleController(int number) { }\n"
|
||||||
|
+ " ~~~~~~~~~~~~~~~~\n"
|
||||||
|
+ "1 errors, 0 warnings\n"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -106,11 +105,11 @@ public class ControllerDetectorTest {
|
|||||||
.files(controllerStub, java(baseClass), java(source))
|
.files(controllerStub, java(baseClass), java(source))
|
||||||
.issues(ControllerIssueDetector.ISSUE, ControllerChangeHandlerIssueDetector.ISSUE)
|
.issues(ControllerIssueDetector.ISSUE, ControllerChangeHandlerIssueDetector.ISSUE)
|
||||||
.run()
|
.run()
|
||||||
.expect(
|
.expect(""
|
||||||
"src/test/SampleController.java:2: Error: This Controller needs to have either a public default constructor or a public single-argument constructor that takes a Bundle. (test.SampleController) [ValidController]\n" +
|
+ "src/test/SampleController.java:3: Error: This Controller needs to have either a public default constructor or a public single-argument constructor that takes a Bundle. (test.SampleController) [ValidController]\n"
|
||||||
"public class SampleController extends BaseController {\n" +
|
+ " private SampleController() { }\n"
|
||||||
"^\n" +
|
+ " ~~~~~~~~~~~~~~~~\n"
|
||||||
"1 errors, 0 warnings"
|
+ "1 errors, 0 warnings"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +125,12 @@ public class ControllerDetectorTest {
|
|||||||
.files(controllerStub, java(source))
|
.files(controllerStub, java(source))
|
||||||
.issues(ControllerIssueDetector.ISSUE, ControllerChangeHandlerIssueDetector.ISSUE)
|
.issues(ControllerIssueDetector.ISSUE, ControllerChangeHandlerIssueDetector.ISSUE)
|
||||||
.run()
|
.run()
|
||||||
.expect(CONSTRUCTOR_ERROR);
|
.expect(""
|
||||||
|
+ "src/test/SampleController.java:3: Error: This Controller needs to have either a public default constructor or a public single-argument constructor that takes a Bundle. (test.SampleController) [ValidController]\n"
|
||||||
|
+ " private SampleController() { }\n"
|
||||||
|
+ " ~~~~~~~~~~~~~~~~\n"
|
||||||
|
+ "1 errors, 0 warnings\n"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user