Giter Club home page Giter Club logo

ethlint's People

Contributors

alonski avatar cgewecke avatar chihchengliang avatar cisplatin avatar come-maiz avatar duaraghav8 avatar federicobond avatar fvictorio avatar gabrielalacchi avatar jooray avatar mushketyk avatar nemani avatar nuevoalex avatar romaric-juniet avatar sohkai avatar utkarsh23 avatar zzq0826 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ethlint's Issues

Import statements 2-line gap rule applies to individual statements and not to the block

Import statement blocks should be succeeded by a 2-line gap but not each import statement as the rules currently enforce.

For example

import "A.sol";
import "B.sol";
import "C.sol";


contract D { [...] }

generate the warnings:


FILE:   /D.sol
--------------------------------------------------------------------------------------------

[WARNING] At line: 1, column: 0 -> ImportStatement must be succeeded by a 2-line gap.

[WARNING] At line: 2, column: 0 -> ImportStatement must be succeeded by a 2-line gap.

[WARNING] At line: 3, column: 0 -> ImportStatement must be succeeded by a 2-line gap.

Add support for reading input from stdin

This is useful for integrating with text editors and IDEs, as it allows linting from the latest buffer contents instead of the data on disk.

It could be implemented with an option named --stdin. For example:

cat MyContract.sol | solium --stdin

unpacking values causes SyntaxError

I have a following file:

contract Test {
    function Test() {
        var (x, y) = doTest();
    }

    function doTest() returns (uint, uint) {
        return (1, 2);
    }
}

which causes an error:

An error occured while running the linter on contracts/test.sol:
Error: An error occured while parsing the source code:
SyntaxError: Expected ")" but "," found. Line: 3, Column: 15

I guess this error is internally in the solparse library, but I'm not sure.

Implement exception for 'Use of empty block statement {}' rule for a payable fallback function

Since Solidity 4 we are able to implement an empty payable fallback function

  function ()
  payable {}

Functionality defined in
http://solidity.readthedocs.io/en/develop/frequently-asked-questions.html?highlight=payable#what-is-the-deal-with-function-inside-solidity-contracts-how-can-a-function-not-have-a-name

This however throws a warning in solium
[WARNING] At line: x, column: y -> Use of empty block statement {}

Linter Integrations for other tools

3rd party

  • Truffle
  • Grunt
  • Gulp
  • Embark
  • Zeppelin
  • Yeoman
  • Webpack
  • Github
  • JetBrains IDEA plugin
  • Atom
  • Sublime
  • Visual Studio

If you're working on any of these (even if they're already done), let us know. We'd love to give you a shout out on our Community Page

"opening brace on same line" error even when the condition spans over multiple lines

if (
    lorem &&
    ipsum > 100 &&
    dolor === 'hello'
) {
    foo ();
}

Above code is (wrongly) flagged by the brace-on-same-line rule. This style is perfectly fine and shouldn't be flagged because we may have conditions too big to fit in a single line.

what kind of a pathetic soul does one have to be to be incapable of thinking of edge cases before they start writing code :'(

doesn't parse 'uint [] x'

uint[] x is parsed, but space between uint & sq brackets throws "unexpected token" error
to fix in solparse

Problems with existing rule implementations

  • operator-whitespace: currently doesn't support 0 space on either side (this is useful when we wish to denote precedence). For eg- it allows 4 * 3 + 19 but doesn't allow 4*3 + 19. Fix this.
  • Column information is not accurate. See issue on solparse

indentation's not perfect yet

for eg- ObjectExpression or StructDeclaration doesn't get linted for indentation:

struct Foo ({
    hello: 'world'
});

same for ArrayExpression that span over multiple lines:

uint[] ages = [
    19,
    20
];

same for CallExpression

foo ({
    'hello': 'world'
});

something like this shouldn't bypass the wrath of solium:

foo (
    "hello", "world", "mofo"
);

1 arg per line, if you're spreading your function call over multiple line. Need to code logic for this too

if (true)
    hello();

Also read #122

without block statement, indentation raises error saying no indent before "hello()" which shouldn't happen

indentation is a bitch o.O

grammatical error

When run solium:
An error occurRed while running the linter on...

False positive for "blank line" missing after a function declaration

This wasn't happening before v1.6 but now it is. The code below will give me a FunctionDeclaration must be succeeded by 1 blank line

/// @notice this function returns something important
/// @return description
function someFunction() constant returns(uint256) {
    return 1;
}

  /// @notice gets something else important
  function anotherFunction() constant returns(uint256)
  {
    return 2;
  }

Accept contract names with numbers

I have no reason to think that names like MyToken2 are invalid according to the style guide.

We should expand the camel case regex to accept this and other variations.

TypeError: Cannot read property '0' of undefined

When I ran the following command:

$ solium --file BlindAuction.sol

The result is:

An error occurred while running the linter on BlindAuction.sol:
TypeError: Cannot read property '0' of undefined
    at EventEmitter.<anonymous> (/usr/local/lib/node_modules/solium/lib/rules/operator-whitespace.js:24:84)
    at emitOne (events.js:96:13)
    at EventEmitter.emit (events.js:188:7)
    at EventGenerator.enterNode (/usr/local/lib/node_modules/solium/lib/utils/node-event-generator.js:25:16)
    at Controller.enter (/usr/local/lib/node_modules/solium/lib/solium.js:101:24)
    at Controller.exec (/usr/local/lib/node_modules/solium/node_modules/sol-explore/lib/traverse.js:99:21)
    at Controller.traverse (/usr/local/lib/node_modules/solium/node_modules/sol-explore/lib/traverse.js:123:17)
    at /usr/local/lib/node_modules/solium/node_modules/sol-explore/lib/traverse.js:137:17
    at Array.forEach (native)
    at Controller.traverse (/usr/local/lib/node_modules/solium/node_modules/sol-explore/lib/traverse.js:133:22)

The source code of BlindAuction.sol is the same as that in the official tutorial here:

pragma solidity ^0.4.0;

contract BlindAuction {
    struct Bid {
        bytes32 blindedBid;
        uint deposit;
    }

    address public beneficiary;
    uint public auctionStart;
    uint public biddingEnd;
    uint public revealEnd;
    bool public ended;

    mapping(address => Bid[]) public bids;

    address public highestBidder;
    uint public highestBid;

    // Allowed withdrawals of previous bids
    mapping(address => uint) pendingReturns;

    event AuctionEnded(address winner, uint highestBid);

    /// Modifiers are a convenient way to validate inputs to
    /// functions. `onlyBefore` is applied to `bid` below:
    /// The new function body is the modifier's body where
    /// `_` is replaced by the old function body.
    modifier onlyBefore(uint _time) { if (now >= _time) throw; _; }
    modifier onlyAfter(uint _time) { if (now <= _time) throw; _; }

    function BlindAuction(
        uint _biddingTime,
        uint _revealTime,
        address _beneficiary
    ) {
        beneficiary = _beneficiary;
        auctionStart = now;
        biddingEnd = now + _biddingTime;
        revealEnd = biddingEnd + _revealTime;
    }

    /// Place a blinded bid with `_blindedBid` = keccak256(value,
    /// fake, secret).
    /// The sent ether is only refunded if the bid is correctly
    /// revealed in the revealing phase. The bid is valid if the
    /// ether sent together with the bid is at least "value" and
    /// "fake" is not true. Setting "fake" to true and sending
    /// not the exact amount are ways to hide the real bid but
    /// still make the required deposit. The same address can
    /// place multiple bids.
    function bid(bytes32 _blindedBid)
        payable
        onlyBefore(biddingEnd)
    {
        bids[msg.sender].push(Bid({
            blindedBid: _blindedBid,
            deposit: msg.value
        }));
    }

    /// Reveal your blinded bids. You will get a refund for all
    /// correctly blinded invalid bids and for all bids except for
    /// the totally highest.
    function reveal(
        uint[] _values,
        bool[] _fake,
        bytes32[] _secret
    )
        onlyAfter(biddingEnd)
        onlyBefore(revealEnd)
    {
        uint length = bids[msg.sender].length;
        if (
            _values.length != length ||
            _fake.length != length ||
            _secret.length != length
        ) {
            throw;
        }

        uint refund;
        for (uint i = 0; i < length; i++) {
            var bid = bids[msg.sender][i];
            var (value, fake, secret) =
                    (_values[i], _fake[i], _secret[i]);
            if (bid.blindedBid != keccak256(value, fake, secret)) {
                // Bid was not actually revealed.
                // Do not refund deposit.
                continue;
            }
            refund += bid.deposit;
            if (!fake && bid.deposit >= value) {
                if (placeBid(msg.sender, value))
                    refund -= value;
            }
            // Make it impossible for the sender to re-claim
            // the same deposit.
            bid.blindedBid = 0;
        }
        if (!msg.sender.send(refund))
            throw;
    }

    // This is an "internal" function which means that it
    // can only be called from the contract itself (or from
    // derived contracts).
    function placeBid(address bidder, uint value) internal
            returns (bool success)
    {
        if (value <= highestBid) {
            return false;
        }
        if (highestBidder != 0) {
            // Refund the previously highest bidder.
            pendingReturns[highestBidder] += highestBid;
        }
        highestBid = value;
        highestBidder = bidder;
        return true;
    }

    /// Withdraw a bid that was overbid.
    function withdraw() returns (bool) {
        var amount = pendingReturns[msg.sender];
        if (amount > 0) {
            // It is important to set this to zero because the recipient
            // can call this function again as part of the receiving call
            // before `send` returns (see the remark above about
            // conditions -> effects -> interaction).
            pendingReturns[msg.sender] = 0;

            if (!msg.sender.send(amount)){
                // No need to call throw here, just reset the amount owing
                pendingReturns[msg.sender] = amount;
                return false;
            }
        }
        return true;
    }

    /// End the auction and send the highest bid
    /// to the beneficiary.
    function auctionEnd()
        onlyAfter(revealEnd)
    {
        if (ended)
            throw;
        AuctionEnded(highestBidder, highestBid);
        ended = true;
        // We send all the money we have, because some
        // of the refunds might have failed.
        if (!beneficiary.send(this.balance))
            throw;
    }
}

Numbers not allowed in mixedCase notation

I suspect this is the reason Solium reports a warning for a function named: throwIfIsEmptyBytes32

[WARNING] At line: 32, column: 2 -> 'throwIfIsEmptyBytes32' doesn't follow the mixedCase notation

Shit to be done

  • Write Test for lib/cli.js
  • Enable ignoring of specific lines in code file which are accompanied by comment //solium-ignore or something like that
  • Lint rules should comply with official Solidity Style guide
  • whitespace rule: add check for space before smicolon and comma in ImportStatement & UsingStatement
  • add contract IUpgradable { function upgrade(address newAddress); } in accepted in lbrace tests
  • For fuck's sake document & test rules as well
  • Update the developer guide to list the newly added functions accessible through context
  • raise issue on solidity-parser: ObjectExpression properties missing type field
  • re-implement operator-whitespace rule
  • Write tests for astUtils.getEndingColumn ()
  • whitespace rule should lint FunctionDeclaration params the same way as CallExpression.
  • If rule programmer sets column: 0, column info gets fucked because we're using condition like location.column || alternative, fix this
  • When exceptions occur, send messages with e.stack instead of e (for stack info)
  • Possibly introduce getEndingLine (node) in SourceCode object - return the line no. where node's code ends
  • reporter displays file name even if that file has no lint errors
  • Update unit test for astUtils.getColumn () once column information logic is added to solparse/solidity-parser
  • Write Unit Tests (should.js maybe?)
  • CLI should Solium.report () all caught exceptions instead of console.log()ing them. Solium.lint () should be called with noReset = true (so it doesn't wipe out the error messages) the first time its called
  • Make column numbers in rule implementations more accurate (currently most of them simply point to the start of line i.e., are 0)
  • Rule refinement: modifier names should follow mixedCase, not CamelCase. Make changes.
  • add --sync option, so every time a new rule is added, user doesn't have to manually add this rule into .soliumrc.json
  • SELF ACTUALIZATION: Use node.end for previous node in rules like blank-lines & indentation
  • --dir option to select particular directory to lint files of
  • Improve error reporting with ^ pointing at the starting character of rule violation
  • Improve docs - add variable name in the @returns field & document the CLI engine
  • Provide fix Interface to rule implementer so they can define a fix for the lint error
  • Stop using console.log in the CLI engine. use a centralized Log object for printing purposes.
  • Rules need to be more descriptive
  • Re-design user configuration to enable easy plug-in of custom lint rules
  • Hot loading --hot in CLI
  • Docs - Usage & Developer Guide
  • Provide ast-utils' getParent() to rule via context object
  • Provide example of getSourceCode () functionality in sample rules
  • SourceCode object - add getNextChars (), getNextChar (), getPrevChars (), getPrevChar ()
  • Add option to ignore particular files while linting the project (this feature has now been removed)
  • Shareable configs
  • Style choices for user (eg- tabs vs. space)

Recognise Contract names in code

Contract names should be CamelCase, and that's what Solium applies for the contract definition, however it appears to not recognise Contract names used outside of the contract X syntax, as for the following

contract MyContract is IMyContract, IMyOtherContract {... }

throws a warning

 'IMyContract' doesn't follow the mixedCase notation
 'IMyOtherContract' doesn't follow the mixedCase notation

Rules Wishlist

This is my wishlist for additional rules. Let me know if you are against any of them getting implemented in the core. I will work on some of them but anything else is up for grabs.

  • Suggest send instead of dangerous call.value() (WIP @federicobond)
  • Suggest avoiding block.timestamp as it can be manipulated by miners (only in functions) (WIP @federicobond)
  • Ensure any function that uses msg.value has payable modifier (WIP @federicobond)
  • Ensure fallback function has payable modifier (WIP @federicobond)
  • Ensure send return value is checked.
  • Extract magic number to constant
  • Suggest using selfdestruct instead of deprecated suicide (WIP @federicobond)
  • Suggest better storage packing (see Warning here)
  • Find duplicate code (this one is hard, perhaps we can write a generic implementation and then integrate it into solium)

A confusing warning about constructors

When a contract has a constructor, a warning informs the user, that it should follow the mixedCase convention:

contract Test {
    function Test() {
        /* my awesome constructor */
    }
}

and the warning:

[WARNING] At line: 2, column: 4 -> 'Test' doesn't follow the mixedCase notation

BlockStatement node.start property doesn't include opening brace in case of FunctionDeclaration

'function foo () { bar (); }'

AST Node:

{
  "type": "FunctionDeclaration",
  "name": "foo",
  "params": null,
  "modifiers": null,
  "body": {
    "type": "BlockStatement",
    "body": [
      {
        "type": "ExpressionStatement",
        "expression": {
          "type": "CallExpression",
          "callee": {
            "type": "Identifier",
            "name": "bar",
            "start": 18,
            "end": 21
          },
          "arguments": [],
          "start": 18,
          "end": 24
        },
        "start": 18,
        "end": 25
      }
    ],
    "start": 18,
    "end": 25
  },
  "is_abstract": false,
  "start": 0,
  "end": 27
}

node.body.start is 18, should've been 16. Same problem with node.body.end.
The braces '{' & '}' are not included in FunctionDeclaration's BlockStatement

Address types treated as Strings

Using 0x0 for an address type variable results in

String Literals must be quoted with double quotes only.

Code sample

function myFunction(address x)
  {
    if(x == 0x0) { throw; }
  }

incorrect node.right in ExpressionStatement

x [0] = fooBar ().baz;

In the code above, .baz is a MemberExpression which causes node.right.start to be incorrect.
The AST for above code is:

{
  "type": "ExpressionStatement",
  "expression": {
    "type": "AssignmentExpression",
    "operator": "=",
    "left": {
      "type": "MemberExpression",
      "object": {
        "type": "Identifier",
        "name": "x",
        "start": 0,
        "end": 1
      },
      "property": {
        "type": "Literal",
        "value": 0,
        "start": 3,
        "end": 4
      },
      "computed": true,
      "start": 0,
      "end": 5
    },
    "right": {
      "type": "MemberExpression",
      "property": {
        "type": "Identifier",
        "name": "baz",
        "start": 18,
        "end": 21
      },
      "computed": false,
      "start": 17,
      "end": 21,
      "object": {
        "type": "CallExpression",
        "callee": {
          "type": "Identifier",
          "name": "fooBar",
          "start": 8,
          "end": 14
        },
        "arguments": [],
        "start": 8,
        "end": 17
      }
    },
    "start": 0,
    "end": 21
  },
  "start": 0,
  "end": 22
}

node.right is the MemberExpression instead of CallExpression (because of fooBar ()).

using a Library 'for' causes SyntaxError

Having a

using LibraryContract **for** someDataType;

As described here http://solidity.readthedocs.io/en/latest/contracts.html?#using-for

causes a SyntaxError:

Error: An error occured while parsing the source code:
SyntaxError: Expected "!=", "!==", "%", "%=", "&", "&&", "&=", "*", "*=", "+", "++", "+=", ",", "-", "--", "-=", "/", "/*", "//", "/=", ";", "<", "<<", "<<=", "<=", "=", "==", "===", ">", ">=", ">>", ">>=", ">>>", ">>>=", "?", "^", "^=", "in", "instanceof", "|", "|=", "||", comment, end of line or whitespace but "f" found. Line: 25, Column: 21
An error occured while running the linter on /MyContract.sol:

rule "whitespace" needs to be re-written

remove rule operator-whitespace and merge its logic into whitespace

whitespace rule must comply with all tests written (currently not uploaded)

array-declarations rule's check for whitespace uint[ ] x must be shifted to whitespace

Rename --hot to --watch

This is probably a matter of opinion, but most tools use the word "watch", as in "watching files" for this functionality. Hot sounds more like code auto-reloading to me.

If you want to keep --hot for backward compatibility, we could configure it as an alias.

What do you think?

A better User Env

The commandline displays simple text.
Maybe coloured text would be more helpful.

Red: Fatal Errors
Blue: Lint/Style errors

false positive in whitespace

newNumber = (10 * 78 + 982 % 6**2);

says '=' must be succeeded by exactly a single space.

when we remove the opening bracket '(' (and the closing obvio), then its all fine.

It treats '(' as whitespace, modify rule!!

Allow uppercase acronyms in contract names

The style guide doesn't specify whether all uppercase acronyms are acceptable in contract names (e.g. IOUToken). Personally I find nothing wrong with it.

What do you think?

"no-unused-vars" rule false positive in inherited contracts

I get an [ERROR] At line: x, column: y -> Variable 'someAddress' is declared but never used. in the scenario below, in which the variable is used in contracts inheriting from the base but not in the base contract itself.

contract IMyContract {

  address public someAddress;

  function myFunction(address someVariable);
}

import 'IMyContract.sol';
contract MyContract is IMyContract {
  function someOtherFunction(address X)
  {
    someAddress = X;
  }
}

Custom rules should follow the same API than core rules

Custom rules should export an object with a verify key. This would make it easy to eventually expand the API so that custom rules provide their own automated fixing code and other features planned for core rules.

We could support passing a function for backwards compatibility but deprecate that usage slowly.

Error thrown when contract name starts with `I`

An error occured while running the linter on /Users/Elena/colonyDapp/truffle/contracts/IMyFactory.sol:
Error: null is not a valid AST node
An error occured while running the linter on /Users/Elena/colonyDapp/truffle/contracts/IMyResolver.sol:
Error: null is not a valid AST node

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.