Skip to content
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 67 additions & 1 deletion src/dscanner/analysis/function_attributes.d
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
module dscanner.analysis.function_attributes;

import dscanner.analysis.base;
import dscanner.analysis.helpers;
import dparse.ast;
import dparse.lexer;
import std.stdio;
Expand Down Expand Up @@ -35,17 +36,45 @@ final class FunctionAttributeCheck : BaseAnalyzer
override void visit(const InterfaceDeclaration dec)
{
const t = inInterface;
const t2 = inAggregate;
inInterface = true;
inAggregate = true;
dec.accept(this);
inInterface = t;
inAggregate = t2;
}

override void visit(const ClassDeclaration dec)
{
const t = inInterface;
const t2 = inAggregate;
inInterface = false;
inAggregate = true;
dec.accept(this);
inInterface = t;
inAggregate = t2;
}

override void visit(const StructDeclaration dec)
{
const t = inInterface;
const t2 = inAggregate;
inInterface = false;
inAggregate = true;
dec.accept(this);
inInterface = t;
inAggregate = t2;
}

override void visit(const UnionDeclaration dec)
{
const t = inInterface;
const t2 = inAggregate;
inInterface = false;
inAggregate = true;
dec.accept(this);
inInterface = t;
inAggregate = t2;
}

override void visit(const AttributeDeclaration dec)
Expand All @@ -59,7 +88,7 @@ final class FunctionAttributeCheck : BaseAnalyzer

override void visit(const FunctionDeclaration dec)
{
if (dec.parameters.parameters.length == 0)
if (dec.parameters.parameters.length == 0 && inAggregate)
{
bool foundConst;
bool foundProperty;
Expand Down Expand Up @@ -115,6 +144,43 @@ final class FunctionAttributeCheck : BaseAnalyzer

private:
bool inInterface;
bool inAggregate;
enum string ABSTRACT_MESSAGE = "'abstract' attribute is redundant in interface declarations";
enum string KEY = "dscanner.confusing.function_attributes";
}

unittest
{
import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;

StaticAnalysisConfig sac = disabledConfig();
sac.function_attribute_check = Check.enabled;
assertAnalyzerWarnings(q{
int foo() @property { return 0; }
const int confusingConst() { return 0; } // [warn]: 'const' is not an attribute of the return type. Place it after the parameter list to clarify.

class ClassName {
int bar() @property { return 0; } // [warn]: Zero-parameter '@property' function should be marked 'const', 'inout', or 'immutable'.
int barConst() const @property { return 0; }
}

struct StructName {
int bar() @property { return 0; } // [warn]: Zero-parameter '@property' function should be marked 'const', 'inout', or 'immutable'.
int barConst() const @property { return 0; }
}

union UnionName {
int bar() @property { return 0; } // [warn]: Zero-parameter '@property' function should be marked 'const', 'inout', or 'immutable'.
int barConst() const @property { return 0; }
}

interface InterfaceName {
int bar() @property; // [warn]: Zero-parameter '@property' function should be marked 'const', 'inout', or 'immutable'.
int barConst() const @property;

abstract int method(); // [warn]: 'abstract' attribute is redundant in interface declarations
}
}c, sac);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you also test static methods? (as mentioned in #791)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


stderr.writeln("Unittest for FunctionAttributeCheck passed.");
}